Collider Component Inspector, Editor routine #88
|
@ -12,6 +12,7 @@
|
||||||
#include "Editor/IconsMaterialDesign.h"
|
#include "Editor/IconsMaterialDesign.h"
|
||||||
#include "ECS_Base/Components/SHComponent.h"
|
#include "ECS_Base/Components/SHComponent.h"
|
||||||
#include "Editor/SHEditorWidgets.hpp"
|
#include "Editor/SHEditorWidgets.hpp"
|
||||||
|
#include "Physics/Components/SHColliderComponent.h"
|
||||||
#include "Reflection/SHReflectionMetadata.h"
|
#include "Reflection/SHReflectionMetadata.h"
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -45,7 +46,7 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
if (!component)
|
if (!component)
|
||||||
return;
|
return;
|
||||||
auto componentType = rttr::type::get(*component);
|
const auto componentType = rttr::type::get(*component);
|
||||||
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
|
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::CollapsingHeader(componentType.get_name().data()))
|
if (ImGui::CollapsingHeader(componentType.get_name().data()))
|
||||||
|
@ -190,4 +191,69 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
else DrawContextMenu(component);
|
else DrawContextMenu(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
static void DrawComponent(SHColliderComponent* component)
|
||||||
|
{
|
||||||
|
if (!component)
|
||||||
|
return;
|
||||||
|
const auto componentType = rttr::type::get(*component);
|
||||||
|
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::CollapsingHeader(componentType.get_name().data()))
|
||||||
|
{
|
||||||
|
DrawContextMenu(component);
|
||||||
|
|
||||||
|
auto& colliders = component->GetColliders();
|
||||||
|
int const size = static_cast<int>(colliders.size());
|
||||||
|
ImGui::BeginChild("Colliders", {0.0f, colliders.empty() ? 1.0f : 250.0f}, true);
|
||||||
|
for (int i{}; i < size; ++i)
|
||||||
|
{
|
||||||
|
SHCollider& collider = component->GetCollider(i);
|
||||||
|
auto cursorPos = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
if (collider.GetType() == SHCollider::Type::BOX)
|
||||||
|
{
|
||||||
|
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_MD_VIEW_IN_AR, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
|
||||||
|
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
|
||||||
|
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);});
|
||||||
|
}
|
||||||
|
else if (collider.GetType() == SHCollider::Type::SPHERE)
|
||||||
|
{
|
||||||
|
SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
|
||||||
|
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider.GetShape());
|
||||||
|
SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);});
|
||||||
|
}
|
||||||
|
else if (collider.GetType() == SHCollider::Type::CAPSULE)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
{
|
||||||
|
SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f });
|
||||||
|
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); });
|
||||||
|
SHEditorWidgets::EndPanel();
|
||||||
|
}
|
||||||
|
if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
|
||||||
|
{
|
||||||
|
component->RemoveCollider(i);
|
||||||
|
}
|
||||||
|
SHEditorWidgets::EndPanel();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Add Collider"))
|
||||||
|
{
|
||||||
|
if(ImGui::Selectable("Box Collider"))
|
||||||
|
{
|
||||||
|
component->AddBoundingBox();
|
||||||
|
}
|
||||||
|
if(ImGui::Selectable("Sphere Collider"))
|
||||||
|
{
|
||||||
|
component->AddBoundingSphere();
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else DrawContextMenu(component);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,12 +24,15 @@
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
|
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
|
||||||
void DrawAddComponentButton(EntityID const& eid)
|
bool DrawAddComponentButton(EntityID const& eid)
|
||||||
{
|
{
|
||||||
if(!SHComponentManager::HasComponent<ComponentType>(eid) && ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()))
|
bool selected = false;
|
||||||
|
if(!SHComponentManager::HasComponent<ComponentType>(eid))
|
||||||
{
|
{
|
||||||
|
if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
|
||||||
SHComponentManager::AddComponent<ComponentType>(eid);
|
SHComponentManager::AddComponent<ComponentType>(eid);
|
||||||
}
|
}
|
||||||
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHEditorInspector::SHEditorInspector()
|
SHEditorInspector::SHEditorInspector()
|
||||||
|
@ -47,11 +50,6 @@ namespace SHADE
|
||||||
SHEditorWindow::Update();
|
SHEditorWindow::Update();
|
||||||
if (Begin())
|
if (Begin())
|
||||||
{
|
{
|
||||||
if (ImGui::Button("AUDIO"))
|
|
||||||
{
|
|
||||||
auto audioSystem = SHSystemManager::GetSystem<SHADE::SHAudioSystem>();
|
|
||||||
audioSystem->PlayEventOnce("event:/Characters/sfx_footsteps_raccoon");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SHEditor::selectedEntities.empty())
|
if (!SHEditor::selectedEntities.empty())
|
||||||
{
|
{
|
||||||
|
@ -90,7 +88,13 @@ namespace SHADE
|
||||||
DrawAddComponentButton<SHTransformComponent>(eid);
|
DrawAddComponentButton<SHTransformComponent>(eid);
|
||||||
DrawAddComponentButton<SHRenderable>(eid);
|
DrawAddComponentButton<SHRenderable>(eid);
|
||||||
DrawAddComponentButton<SHColliderComponent>(eid);
|
DrawAddComponentButton<SHColliderComponent>(eid);
|
||||||
DrawAddComponentButton<SHRigidBodyComponent>(eid);
|
if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
|
||||||
|
{
|
||||||
|
if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr)
|
||||||
|
{
|
||||||
|
SHComponentManager::AddComponent<SHTransformComponent>(eid);
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ namespace SHADE
|
||||||
ImFont* mainFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path
|
ImFont* mainFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path
|
||||||
|
|
||||||
static const ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
|
static const ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
|
||||||
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.PixelSnapH = true;
|
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f;
|
||||||
ImFont* UIFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path
|
ImFont* UIFont = io.Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path
|
||||||
|
|
||||||
io.Fonts->Build();
|
io.Fonts->Build();
|
||||||
|
|
|
@ -35,6 +35,118 @@ namespace SHADE
|
||||||
//#==============================================================#
|
//#==============================================================#
|
||||||
//|| Custom Widgets ||
|
//|| Custom Widgets ||
|
||||||
//#==============================================================#
|
//#==============================================================#
|
||||||
|
inline static ImVector<ImRect> panelStack{};
|
||||||
|
static void BeginPanel(std::string_view const& name, const ImVec2& size)
|
||||||
|
{
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
auto cursorPos = ImGui::GetCursorScreenPos();
|
||||||
|
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||||
|
|
||||||
|
auto frameHeight = ImGui::GetFrameHeight();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
ImVec2 effectiveSize = size;
|
||||||
|
if (size.x < 0.0f)
|
||||||
|
effectiveSize.x = ImGui::GetContentRegionAvail().x;
|
||||||
|
else
|
||||||
|
effectiveSize.x = size.x;
|
||||||
|
ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f));
|
||||||
|
|
||||||
|
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
|
||||||
|
ImGui::SameLine(0.0f, 0.0f);
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
|
||||||
|
ImGui::SameLine(0.0f, 0.0f);
|
||||||
|
ImGui::TextUnformatted(name.data());
|
||||||
|
auto labelMin = ImGui::GetItemRectMin();
|
||||||
|
auto labelMax = ImGui::GetItemRectMax();
|
||||||
|
ImGui::SameLine(0.0f, 0.0f);
|
||||||
|
ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y));
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
|
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f;
|
||||||
|
ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f;
|
||||||
|
ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f;
|
||||||
|
|
||||||
|
ImGui::GetCurrentWindow()->Size.x -= frameHeight;
|
||||||
|
|
||||||
|
auto itemWidth = ImGui::CalcItemWidth();
|
||||||
|
ImGui::PushItemWidth(ImMax(0.0f, itemWidth - frameHeight));
|
||||||
|
|
||||||
|
panelStack.push_back(ImRect(labelMin, labelMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EndPanel()
|
||||||
|
{
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
auto itemSpacing = ImGui::GetStyle().ItemSpacing;
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||||
|
|
||||||
|
auto frameHeight = ImGui::GetFrameHeight();
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SameLine(0.0f, 0.0f);
|
||||||
|
ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
|
||||||
|
ImGui::Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y));
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
auto itemMin = ImGui::GetItemRectMin();
|
||||||
|
auto itemMax = ImGui::GetItemRectMax();
|
||||||
|
|
||||||
|
auto labelRect = panelStack.back();
|
||||||
|
panelStack.pop_back();
|
||||||
|
|
||||||
|
ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f;
|
||||||
|
ImRect frameRect = ImRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f));
|
||||||
|
labelRect.Min.x -= itemSpacing.x;
|
||||||
|
labelRect.Max.x += itemSpacing.x;
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
// left half-plane
|
||||||
|
case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break;
|
||||||
|
// right half-plane
|
||||||
|
case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break;
|
||||||
|
// top
|
||||||
|
case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, -FLT_MAX), ImVec2(labelRect.Max.x, labelRect.Min.y), true); break;
|
||||||
|
// bottom
|
||||||
|
case 3: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::GetWindowDrawList()->AddRect(
|
||||||
|
frameRect.Min, frameRect.Max,
|
||||||
|
ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Button)),
|
||||||
|
halfFrame.x);
|
||||||
|
|
||||||
|
ImGui::PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
|
ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f;
|
||||||
|
ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f;
|
||||||
|
ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f;
|
||||||
|
|
||||||
|
ImGui::GetCurrentWindow()->Size.x += frameHeight;
|
||||||
|
|
||||||
|
ImGui::Dummy(ImVec2(0.0f, 0.0f));
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f)
|
static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f)
|
||||||
{
|
{
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
|
|
Loading…
Reference in New Issue