#include "InspectorPanel.h" #include "Managers/SceneManager.h" #include "Managers/SelectionManager.h" #include "UI/UI.h" #include #include #include #include #include static LONG WINAPI CrashExceptionFilter(EXCEPTION_POINTERS* exceptionPointers) { char buffer[1024]; std::snprintf(buffer, sizeof(buffer), "[CRASH] ExceptionCode=0x%08X, Address=0x%p", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress); FILE* f = fopen("D:\\Xuanchi\\Main\\XCEngine\\editor\\bin\\Release\\crash.log", "a"); if (f) { fprintf(f, "%s\n", buffer); fclose(f); } fprintf(stderr, "%s\n", buffer); return EXCEPTION_EXECUTE_HANDLER; } namespace XCEngine { namespace Editor { InspectorPanel::InspectorPanel() : Panel("Inspector") { Debug::Logger::Get().Debug(Debug::LogCategory::General, "InspectorPanel constructed"); m_selectionHandlerId = SelectionManager::Get().OnSelectionChanged.Subscribe([this](uint64_t) { m_selectedGameObject = SelectionManager::Get().GetSelectedEntity(); }); } InspectorPanel::~InspectorPanel() { SelectionManager::Get().OnSelectionChanged.Unsubscribe(m_selectionHandlerId); } void InspectorPanel::Render() { Debug::Logger::Get().Debug(Debug::LogCategory::General, "InspectorPanel::Render START"); ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None); m_selectedGameObject = SelectionManager::Get().GetSelectedEntity(); if (m_selectedGameObject) { RenderGameObject(m_selectedGameObject); } else { ImGui::Text("No object selected"); ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Select an object in Hierarchy"); } ImGui::End(); Debug::Logger::Get().Debug(Debug::LogCategory::General, "InspectorPanel::Render END"); } void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameObject) { Debug::Logger::Get().Debug(Debug::LogCategory::General, "RenderGameObject START"); char nameBuffer[256]; strcpy_s(nameBuffer, gameObject->GetName().c_str()); ImGui::InputText("##Name", nameBuffer, sizeof(nameBuffer)); if (ImGui::IsItemDeactivatedAfterEdit()) { gameObject->SetName(nameBuffer); } ImGui::SameLine(); if (ImGui::Button("Add Component")) { Debug::Logger::Get().Debug(Debug::LogCategory::General, "Add Component BUTTON CLICKED"); ImGui::OpenPopup("AddComponent"); } RenderAddComponentPopup(gameObject); auto components = gameObject->GetComponents<::XCEngine::Components::Component>(); for (auto* component : components) { RenderComponent(component, gameObject); } Debug::Logger::Get().Debug(Debug::LogCategory::General, "RenderGameObject END"); } void InspectorPanel::RenderAddComponentPopup(::XCEngine::Components::GameObject* gameObject) { Debug::Logger::Get().Debug(Debug::LogCategory::General, "RenderAddComponentPopup called"); if (!gameObject) { Debug::Logger::Get().Error(Debug::LogCategory::General, "ERROR: gameObject is nullptr!"); return; } if (!ImGui::BeginPopup("AddComponent")) { Debug::Logger::Get().Debug(Debug::LogCategory::General, "BeginPopup returned false"); return; } Debug::Logger::Get().Debug(Debug::LogCategory::General, "BeginPopup succeeded"); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f, 10.0f)); ImGui::SeparatorText("Components"); bool hasTransform = gameObject->GetComponent<::XCEngine::Components::TransformComponent>() != nullptr; Debug::Logger::Get().Debug(Debug::LogCategory::General, hasTransform ? "Has Transform: yes" : "Has Transform: no"); Debug::Logger::Get().Debug(Debug::LogCategory::General, "About to check MenuItem condition"); if (ImGui::MenuItem("Transform", nullptr, false, !hasTransform)) { Debug::Logger::Get().Debug(Debug::LogCategory::General, "MenuItem CLICKED! Before AddComponent"); void* newComp = nullptr; __try { newComp = gameObject->AddComponent<::XCEngine::Components::TransformComponent>(); Debug::Logger::Get().Debug(Debug::LogCategory::General, newComp ? "AddComponent SUCCEEDED" : "AddComponent FAILED"); } __except(CrashExceptionFilter(GetExceptionInformation())) { Debug::Logger::Get().Error(Debug::LogCategory::General, "AddComponent CRASHED!"); } ImGui::CloseCurrentPopup(); } else { Debug::Logger::Get().Debug(Debug::LogCategory::General, "MenuItem not clicked (disabled or condition false)"); } ImGui::SeparatorText("Other"); ImGui::TextDisabled("No more components available"); Debug::Logger::Get().Debug(Debug::LogCategory::General, "About to EndPopup"); ImGui::EndPopup(); ImGui::PopStyleVar(); Debug::Logger::Get().Debug(Debug::LogCategory::General, "Popup closed"); } void InspectorPanel::RenderComponent(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject) { if (!component) return; const char* name = component->GetName().c_str(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 2}); ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_AllowOverlap; bool open = ImGui::TreeNodeEx((void*)typeid(*component).hash_code(), flags, "%s", name); ImGui::PopStyleVar(); bool removeComponent = false; if (ImGui::BeginPopupContextItem("ComponentSettings")) { if (ImGui::MenuItem("Remove Component")) { removeComponent = true; } ImGui::EndPopup(); } if (removeComponent) { RemoveComponentByType(component, gameObject); return; } if (open) { if (auto* transform = dynamic_cast<::XCEngine::Components::TransformComponent*>(component)) { ::XCEngine::Math::Vector3 position = transform->GetLocalPosition(); ::XCEngine::Math::Vector3 rotation = transform->GetLocalEulerAngles(); ::XCEngine::Math::Vector3 scale = transform->GetLocalScale(); if (UI::DrawVec3("Position", position, 0.0f, 80.0f, 0.1f)) { transform->SetLocalPosition(position); } if (UI::DrawVec3("Rotation", rotation, 0.0f, 80.0f, 1.0f)) { transform->SetLocalEulerAngles(rotation); } if (UI::DrawVec3("Scale", scale, 1.0f, 80.0f, 0.1f)) { transform->SetLocalScale(scale); } } ImGui::TreePop(); } } void InspectorPanel::RemoveComponentByType(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject) { if (!component || !gameObject) return; if (dynamic_cast<::XCEngine::Components::TransformComponent*>(component)) { return; } auto components = gameObject->GetComponents<::XCEngine::Components::Component>(); for (auto* comp : components) { if (comp == component) { gameObject->RemoveComponent<::XCEngine::Components::Component>(); break; } } } } }