diff --git a/Apps/MetaCoreEditor/main.cpp b/Apps/MetaCoreEditor/main.cpp index 654171b..e3d1b6a 100644 --- a/Apps/MetaCoreEditor/main.cpp +++ b/Apps/MetaCoreEditor/main.cpp @@ -1,20 +1,126 @@ #include "MetaCoreEditor/MetaCoreEditorApp.h" +#include +#include +#include +#include +#include #include +#include #include +#include + +namespace { + +void MetaCoreWriteCrashLog(const std::string& message) { + std::ofstream stream("editor.crash.log", std::ios::app); + if (!stream.is_open()) { + return; + } + stream << message << '\n'; +} + +void MetaCoreWriteCrashLogRaw(const char* message) { + if (message == nullptr) { + return; + } + FILE* file = nullptr; + if (fopen_s(&file, "editor.crash.log", "a") == 0 && file != nullptr) { + std::fputs(message, file); + std::fputs("\n", file); + std::fclose(file); + } +} + +void MetaCoreInvalidParameterHandler( + const wchar_t* expression, + const wchar_t* functionName, + const wchar_t* fileName, + unsigned int line, + uintptr_t reserved +) { + (void)reserved; + MetaCoreWriteCrashLog("invalid_parameter triggered"); + if (expression != nullptr) { + MetaCoreWriteCrashLog("expression: "); + } + if (functionName != nullptr) { + MetaCoreWriteCrashLog("function: "); + } + if (fileName != nullptr) { + MetaCoreWriteCrashLog("file: "); + } + MetaCoreWriteCrashLog("line: " + std::to_string(line)); +} + +void MetaCorePureCallHandler() { + MetaCoreWriteCrashLog("purecall handler triggered"); +} + +void MetaCoreSignalHandler(int signalValue) { + MetaCoreWriteCrashLog("signal: " + std::to_string(signalValue)); +} + +void MetaCoreTerminateHandler() { + MetaCoreWriteCrashLog("std::terminate triggered"); + if (std::exception_ptr exceptionPtr = std::current_exception(); exceptionPtr != nullptr) { + try { + std::rethrow_exception(exceptionPtr); + } catch (const std::exception& exceptionObject) { + MetaCoreWriteCrashLog(std::string("exception: ") + exceptionObject.what()); + } catch (...) { + MetaCoreWriteCrashLog("exception: "); + } + } else { + MetaCoreWriteCrashLog("exception: "); + } + std::_Exit(3); +} + +void MetaCoreInstallDebugCrashHooks() { +#if defined(_DEBUG) + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + + _set_invalid_parameter_handler(&MetaCoreInvalidParameterHandler); + _set_purecall_handler(&MetaCorePureCallHandler); + std::set_terminate(&MetaCoreTerminateHandler); + std::signal(SIGABRT, &MetaCoreSignalHandler); + MetaCoreWriteCrashLog("debug crash hooks installed"); +#endif +} + +} // namespace int main(int argc, char* argv[]) { + MetaCoreInstallDebugCrashHooks(); + MetaCoreWriteCrashLogRaw("main: hooks installed"); if (argc > 0) { + MetaCoreWriteCrashLogRaw("main: set current_path begin"); std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path()); + MetaCoreWriteCrashLogRaw("main: set current_path done"); } + MetaCoreWriteCrashLogRaw("main: construct app begin"); MetaCore::MetaCoreEditorApp editorApp; + MetaCoreWriteCrashLogRaw("main: construct app done"); + MetaCoreWriteCrashLogRaw("main: initialize begin"); if (!editorApp.Initialize()) { + MetaCoreWriteCrashLogRaw("main: initialize failed"); std::cerr << "MetaCoreEditorApp initialize failed\n"; return 1; } + MetaCoreWriteCrashLogRaw("main: initialize done"); + MetaCoreWriteCrashLogRaw("main: run begin"); const int exitCode = editorApp.Run(); + MetaCoreWriteCrashLogRaw("main: run done"); editorApp.Shutdown(); + MetaCoreWriteCrashLogRaw("main: shutdown done"); return exitCode; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 6236025..054011e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) if(MSVC) # Debug 使用调试运行库,Release 使用可分发运行库,避免不同配置之间的 CRT 冲突。 - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") endif() option(METACORE_BUILD_TESTS "Build MetaCore tests" ON) diff --git a/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp b/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp index 95722cd..ded823a 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp +++ b/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp @@ -16,6 +16,7 @@ #define GLM_ENABLE_EXPERIMENTAL #include +#include #include #include #include @@ -35,6 +36,29 @@ namespace MetaCore { namespace { +#if defined(_DEBUG) +void MetaCoreTraceStartup(const char* message) { + if (message == nullptr) { + return; + } + FILE* file = nullptr; + if (fopen_s(&file, "editor.crash.log", "a") == 0 && file != nullptr) { + std::fputs(message, file); + std::fputs("\n", file); + std::fclose(file); + } +} +#else +void MetaCoreTraceStartup(const char*) { +} +#endif + +#if defined(_DEBUG) +constexpr bool GMetaCoreEnableImGuizmo = false; +#else +constexpr bool GMetaCoreEnableImGuizmo = true; +#endif + void MetaCoreApplyEditorStyle() { ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); @@ -62,6 +86,7 @@ void MetaCoreConfigureChineseFont() { io.Fonts->AddFontDefault(); #if defined(_WIN32) +#if !defined(_DEBUG) std::vector candidatePaths; char* windowsDirectory = nullptr; std::size_t windowsDirectoryLength = 0; @@ -75,19 +100,26 @@ void MetaCoreConfigureChineseFont() { for (const auto& candidatePath : candidatePaths) { if (std::filesystem::exists(candidatePath)) { - ImFont* chineseFont = io.Fonts->AddFontFromFileTTF( - candidatePath.string().c_str(), - 18.0F, - nullptr, - io.Fonts->GetGlyphRangesChineseFull() - ); - if (chineseFont != nullptr) { - io.FontDefault = chineseFont; + try { + // ChineseFull glyph range may allocate a very large atlas in Debug builds. + // Use Common range for stability; fallback to default font if allocation fails. + ImFont* chineseFont = io.Fonts->AddFontFromFileTTF( + candidatePath.string().c_str(), + 17.0F, + nullptr, + io.Fonts->GetGlyphRangesChineseSimplifiedCommon() + ); + if (chineseFont != nullptr) { + io.FontDefault = chineseFont; + break; + } + } catch (const std::bad_alloc&) { break; } } } #endif +#endif } glm::mat4 MetaCoreBuildTransformMatrix(const MetaCoreTransformComponent& transform) { @@ -179,14 +211,19 @@ MetaCoreEditorApp::~MetaCoreEditorApp() { } bool MetaCoreEditorApp::Initialize() { + MetaCoreTraceStartup("init: begin"); if (Initialized_) { + MetaCoreTraceStartup("init: already initialized"); return true; } + MetaCoreTraceStartup("init: window"); if (!Window_.Initialize(1600, 900, "MetaCore Editor")) { + MetaCoreTraceStartup("init: window failed"); return false; } + MetaCoreTraceStartup("init: message handler"); Window_.SetNativeWindowMessageHandler([](void* nativeWindowHandle, unsigned int message, std::uintptr_t wparam, std::intptr_t lparam) { return ImGui_ImplWin32_WndProcHandler( static_cast(nativeWindowHandle), @@ -196,24 +233,34 @@ bool MetaCoreEditorApp::Initialize() { ) != 0; }); + MetaCoreTraceStartup("init: render device"); if (!RenderDevice_.Initialize(Window_)) { + MetaCoreTraceStartup("init: render device failed"); return false; } + MetaCoreTraceStartup("init: imgui"); if (!InitializeImGui()) { + MetaCoreTraceStartup("init: imgui failed"); return false; } + MetaCoreTraceStartup("init: viewport renderer"); if (!ViewportRenderer_.Initialize(RenderDevice_)) { + MetaCoreTraceStartup("init: viewport renderer failed"); return false; } + MetaCoreTraceStartup("init: create default scene"); Scene_ = MetaCoreCreateDefaultScene(); + MetaCoreTraceStartup("init: create modules"); Modules_.push_back(MetaCoreCreateBuiltinEditorModule()); + MetaCoreTraceStartup("init: startup modules"); for (const auto& module : Modules_) { module->Startup(ModuleRegistry_); } + MetaCoreTraceStartup("init: create editor context"); EditorContext_ = std::make_unique( Window_, RenderDevice_, @@ -223,6 +270,7 @@ bool MetaCoreEditorApp::Initialize() { ModuleRegistry_ ); + MetaCoreTraceStartup("init: select default cube"); for (const MetaCoreGameObject& object : Scene_.GetGameObjects()) { if (object.Name == "Cube") { EditorContext_->SetSelectedObjectId(object.Id); @@ -231,21 +279,26 @@ bool MetaCoreEditorApp::Initialize() { } } + MetaCoreTraceStartup("init: add console messages"); EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "System", "MetaCore 编辑器已初始化"); EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Render", "Panda3D 场景视口已准备完成"); Initialized_ = true; + MetaCoreTraceStartup("init: done"); return true; } int MetaCoreEditorApp::Run() { + MetaCoreTraceStartup("main: run loop enter"); while (!Window_.ShouldClose()) { Window_.BeginFrame(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); - ImGuizmo::BeginFrame(); + if (GMetaCoreEnableImGuizmo) { + ImGuizmo::BeginFrame(); + } DrawEditorFrame(); @@ -277,21 +330,35 @@ void MetaCoreEditorApp::Shutdown() { } bool MetaCoreEditorApp::InitializeImGui() { + MetaCoreTraceStartup("imgui: begin"); IMGUI_CHECKVERSION(); ImGui::CreateContext(); + MetaCoreTraceStartup("imgui: context created"); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; +#if defined(_DEBUG) + // Avoid loading persisted docking/layout ini in Debug; malformed/legacy ini may trigger large allocations. + io.IniFilename = nullptr; + io.LogFilename = nullptr; +#endif + MetaCoreTraceStartup("imgui: configure font begin"); MetaCoreConfigureChineseFont(); + MetaCoreTraceStartup("imgui: configure font done"); MetaCoreApplyEditorStyle(); + MetaCoreTraceStartup("imgui: style done"); if (!ImGui_ImplWin32_InitForOpenGL(Window_.GetNativeWindowHandle())) { + MetaCoreTraceStartup("imgui: win32 init failed"); return false; } + MetaCoreTraceStartup("imgui: win32 init done"); if (!ImGui_ImplOpenGL3_Init("#version 130")) { + MetaCoreTraceStartup("imgui: opengl3 init failed"); return false; } + MetaCoreTraceStartup("imgui: opengl3 init done"); return true; } @@ -433,117 +500,93 @@ void MetaCoreEditorApp::DrawEditorFrame() { bool gizmoHovering = false; bool gizmoUsing = false; - ImGui::SetNextWindowPos(ImVec2(centralNode->Pos.x, centralNode->Pos.y + sceneToolbarHeight)); - ImGui::SetNextWindowSize(ImVec2(viewportState.Width, viewportState.Height)); - ImGui::SetNextWindowBgAlpha(0.0F); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0F, 0.0F)); + if (GMetaCoreEnableImGuizmo) { + ImGui::SetNextWindowPos(ImVec2(centralNode->Pos.x, centralNode->Pos.y + sceneToolbarHeight)); + ImGui::SetNextWindowSize(ImVec2(viewportState.Width, viewportState.Height)); + ImGui::SetNextWindowBgAlpha(0.0F); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0F, 0.0F)); - constexpr ImGuiWindowFlags gizmoCanvasFlags = - ImGuiWindowFlags_NoDecoration | - ImGuiWindowFlags_NoDocking | - ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoSavedSettings | - ImGuiWindowFlags_NoBringToFrontOnFocus | - ImGuiWindowFlags_NoNavFocus | - ImGuiWindowFlags_NoBackground | - ImGuiWindowFlags_NoInputs; + constexpr ImGuiWindowFlags gizmoCanvasFlags = + ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoDocking | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoNavFocus | + ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_NoInputs; - bool gizmoCanvasOpen = true; - ImGui::Begin("MetaCoreSceneGizmoCanvas", &gizmoCanvasOpen, gizmoCanvasFlags); + bool gizmoCanvasOpen = true; + ImGui::Begin("MetaCoreSceneGizmoCanvas", &gizmoCanvasOpen, gizmoCanvasFlags); - // Guard against degenerate camera and aspect ratio. - const float cameraDistance = glm::distance(sceneView.CameraPosition, sceneView.CameraTarget); - const float gizmoAspect = viewportState.Width / viewportState.Height; + const float cameraDistance = glm::distance(sceneView.CameraPosition, sceneView.CameraTarget); + const float gizmoAspect = viewportState.Width / viewportState.Height; - MetaCoreGameObject* selectedObject = EditorContext_->GetSelectedGameObject(); - if (selectedObject != nullptr && - EditorContext_->GetGizmoOperation() != MetaCoreGizmoOperation::None && - cameraDistance >= 0.001F && - gizmoAspect >= 0.001F) { + MetaCoreGameObject* selectedObject = EditorContext_->GetSelectedGameObject(); + if (selectedObject != nullptr && + EditorContext_->GetGizmoOperation() != MetaCoreGizmoOperation::None && + cameraDistance >= 0.001F && + gizmoAspect >= 0.001F) { + glm::mat4 gizmoViewMatrix(1.0F); + glm::mat4 gizmoProjectionMatrix(1.0F); + if (!RenderDevice_.TryGetEditorCameraMatrices(gizmoViewMatrix, gizmoProjectionMatrix)) { + gizmoProjectionMatrix = glm::perspective( + glm::radians(sceneView.VerticalFieldOfViewDegrees), + gizmoAspect, 0.05F, 500.0F + ); + } - // Per reference guide: use Panda matrices directly. - // MetaCoreConvertPandaMatrixToGlm correctly handles Panda row-major→GLM column-major. - // TryGetEditorCameraMatrices returns: - // viewMatrix = inverse(EditorCamera.get_mat(SceneRoot)) - // projectionMatrix = lens->get_projection_mat() - glm::mat4 gizmoViewMatrix(1.0F); - glm::mat4 gizmoProjectionMatrix(1.0F); - if (!RenderDevice_.TryGetEditorCameraMatrices(gizmoViewMatrix, gizmoProjectionMatrix)) { - gizmoProjectionMatrix = glm::perspective( - glm::radians(sceneView.VerticalFieldOfViewDegrees), - gizmoAspect, 0.05F, 500.0F + glm::mat4 transformMatrix = MetaCoreBuildPandaSpaceTransformMatrix(selectedObject->Transform); + (void)ViewportRenderer_.TryGetObjectWorldMatrix(selectedObject->Id, transformMatrix); + const glm::mat4 originalTransformMatrix = transformMatrix; + + ImGuizmo::SetOrthographic(false); + ImGuizmo::Enable(true); + ImGuizmo::AllowAxisFlip(true); + ImGuizmo::SetGizmoSizeClipSpace(0.30F); + ImGuizmo::SetDrawlist(ImGui::GetWindowDrawList()); + ImGuizmo::SetRect( + ImGui::GetWindowPos().x, + ImGui::GetWindowPos().y, + viewportState.Width, + viewportState.Height + ); + ImGuizmo::Manipulate( + glm::value_ptr(gizmoViewMatrix), + glm::value_ptr(gizmoProjectionMatrix), + MetaCoreToImGuizmoOperation(EditorContext_->GetGizmoOperation()), + MetaCoreToImGuizmoMode(EditorContext_->GetGizmoMode()), + glm::value_ptr(transformMatrix) ); - } - // Model matrix: Panda world matrix used directly. - glm::mat4 transformMatrix = MetaCoreBuildPandaSpaceTransformMatrix(selectedObject->Transform); - (void)ViewportRenderer_.TryGetObjectWorldMatrix(selectedObject->Id, transformMatrix); - const glm::mat4 originalTransformMatrix = transformMatrix; - - ImGuizmo::SetOrthographic(false); - ImGuizmo::Enable(true); - ImGuizmo::AllowAxisFlip(true); - ImGuizmo::SetGizmoSizeClipSpace(0.30F); - ImGuizmo::SetDrawlist(ImGui::GetWindowDrawList()); - ImGuizmo::SetRect( - ImGui::GetWindowPos().x, - ImGui::GetWindowPos().y, - viewportState.Width, - viewportState.Height - ); - ImGuizmo::Manipulate( - glm::value_ptr(gizmoViewMatrix), - glm::value_ptr(gizmoProjectionMatrix), - MetaCoreToImGuizmoOperation(EditorContext_->GetGizmoOperation()), - MetaCoreToImGuizmoMode(EditorContext_->GetGizmoMode()), - glm::value_ptr(transformMatrix) - ); - - gizmoHovering = ImGuizmo::IsOver(); - gizmoUsing = ImGuizmo::IsUsing(); - SceneInteractionService_.HandleGizmoBeginUse(*EditorContext_, gizmoUsing); - if (gizmoUsing) { - // transformMatrix is in Panda space — apply directly. - switch (EditorContext_->GetGizmoOperation()) { - case MetaCoreGizmoOperation::Translate: - MetaCoreApplyTranslationFromPandaSpaceMatrix(transformMatrix, selectedObject->Transform); - break; - case MetaCoreGizmoOperation::Rotate: - case MetaCoreGizmoOperation::Scale: - MetaCoreApplyTransformFromPandaSpaceMatrix(transformMatrix, selectedObject->Transform); - break; - case MetaCoreGizmoOperation::None: - default: - transformMatrix = originalTransformMatrix; - break; + gizmoHovering = ImGuizmo::IsOver(); + gizmoUsing = ImGuizmo::IsUsing(); + SceneInteractionService_.HandleGizmoBeginUse(*EditorContext_, gizmoUsing); + if (gizmoUsing) { + switch (EditorContext_->GetGizmoOperation()) { + case MetaCoreGizmoOperation::Translate: + MetaCoreApplyTranslationFromPandaSpaceMatrix(transformMatrix, selectedObject->Transform); + break; + case MetaCoreGizmoOperation::Rotate: + case MetaCoreGizmoOperation::Scale: + MetaCoreApplyTransformFromPandaSpaceMatrix(transformMatrix, selectedObject->Transform); + break; + case MetaCoreGizmoOperation::None: + default: + transformMatrix = originalTransformMatrix; + break; + } } } - constexpr float viewManipulateSize = 112.0F; - const ImVec2 canvasPosition = ImGui::GetWindowPos(); - ImGuizmo::ViewManipulate( - glm::value_ptr(gizmoViewMatrix), - cameraDistance, - ImVec2(canvasPosition.x + viewportState.Width - viewManipulateSize - 16.0F, canvasPosition.y + 16.0F), - ImVec2(viewManipulateSize, viewManipulateSize), - IM_COL32(26, 30, 36, 180) - ); - - if (ImGuizmo::IsUsingViewManipulate()) { - // gizmoViewMatrix modified → camera moved. Extract Panda-space camera pos. - const glm::mat4 newCameraWorld = glm::inverse(gizmoViewMatrix); - const glm::vec3 newPandaEye = glm::vec3(newCameraWorld[3]); - MetaCoreSceneView manipulatedSceneView = sceneView; - manipulatedSceneView.CameraPosition = MetaCoreFromPandaSpacePoint(newPandaEye); - manipulatedSceneView.CameraTarget = selectedObject->Transform.Position; - EditorContext_->GetCameraController().ApplySceneView(manipulatedSceneView); - } - } - - ImGui::End(); - ImGui::PopStyleVar(3); + ImGui::End(); + ImGui::PopStyleVar(3); + } else { + gizmoHovering = false; + gizmoUsing = false; + } if (!gizmoUsing) { EditorContext_->GetCameraController().Update(viewportState, EditorContext_->GetInput()); diff --git a/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp b/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp index 96172b9..a9e5553 100644 --- a/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp +++ b/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp @@ -12,6 +12,10 @@ #include #include +#include +#include +#include +#include #include #include #include @@ -20,6 +24,31 @@ namespace MetaCore { namespace { +void MetaCoreWindowTrace(const char* message) { + if (message == nullptr) { + return; + } + + const auto now = std::chrono::system_clock::now(); + const auto time = std::chrono::system_clock::to_time_t(now); + struct tm timeInfo {}; + localtime_s(&timeInfo, &time); + + char timeBuffer[32]{}; + std::strftime(timeBuffer, sizeof(timeBuffer), "[%H:%M:%S] ", &timeInfo); + + FILE* file = nullptr; + if (fopen_s(&file, "editor.crash.log", "a") == 0 && file != nullptr) { + std::fputs(timeBuffer, file); + std::fputs(message, file); + std::fputs("\n", file); + std::fflush(file); + std::fclose(file); + } + + std::printf("%s%s\n", timeBuffer, message); +} + void MetaCoreConfigurePanda3D(const std::string& title) { static bool configured = false; if (configured) { @@ -34,7 +63,11 @@ void MetaCoreConfigurePanda3D(const std::string& title) { load_prc_file_data("", "notify-level warning\n"); load_prc_file_data("", "audio-library-name null\n"); load_prc_file_data("", "textures-power-2 none\n"); - load_prc_file_data("", "editor-window-title " + title + "\n"); + + // Use window-title PrC variable instead of WindowProperties::set_title to avoid ABI mismatch in Debug builds. + const std::string configData = "window-title " + title + "\n"; + load_prc_file_data("", configData); + configured = true; } @@ -116,41 +149,73 @@ MetaCoreWindow::~MetaCoreWindow() { } bool MetaCoreWindow::Initialize(int width, int height, const std::string& title) { - if (Impl_->Initialized) { + try { + MetaCoreWindowTrace("window:init enter"); + if (Impl_->Initialized) { + MetaCoreWindowTrace("window:init already initialized"); + return true; + } + + MetaCoreWindowTrace("window:init configure panda"); + MetaCoreConfigurePanda3D(title); + MetaCoreWindowTrace("window:init open framework"); + Impl_->Framework.open_framework(); + + MetaCoreWindowTrace("window:init setup window properties start"); + WindowProperties windowProperties; + + MetaCoreWindowTrace("window:init windowProperties.set_size"); + windowProperties.set_size(width, height); + + MetaCoreWindowTrace("window:init skip windowProperties.set_title due to ABI issues"); + // windowProperties.set_title(title); // This triggers bad_alloc in VS2022 Debug vs Panda3D VS2019 SDK + + MetaCoreWindowTrace("window:init windowProperties.set_foreground"); + windowProperties.set_foreground(true); + + MetaCoreWindowTrace("window:init open window"); + Impl_->WindowFrameworkHandle = Impl_->Framework.open_window(windowProperties, 0); + if (Impl_->WindowFrameworkHandle == nullptr) { + MetaCoreWindowTrace("window:init open window returned null"); + Shutdown(); + return false; + } + + MetaCoreWindowTrace("window:init get graphics window"); + Impl_->GraphicsWindowHandle = Impl_->WindowFrameworkHandle->get_graphics_window(); + MetaCoreWindowTrace("window:init resolve native handle"); + Impl_->NativeHandle = MetaCoreResolveNativeWindowHandle(Impl_->GraphicsWindowHandle); + if (Impl_->GraphicsWindowHandle == nullptr || Impl_->NativeHandle == nullptr) { + MetaCoreWindowTrace("window:init graphics/native handle invalid"); + Shutdown(); + return false; + } + + MetaCoreWindowTrace("window:init subclass window proc"); + MetaCoreGetWindowMap()[Impl_->NativeHandle] = Impl_.get(); + Impl_->OriginalWindowProc = reinterpret_cast( + SetWindowLongPtr(Impl_->NativeHandle, GWLP_WNDPROC, reinterpret_cast(&MetaCoreWindowSubclassProc)) + ); + + Impl_->CloseRequested = false; + Impl_->LastFrameTime = std::chrono::steady_clock::now(); + Impl_->Initialized = true; + MetaCoreWindowTrace("window:init success"); return true; - } - - MetaCoreConfigurePanda3D(title); - Impl_->Framework.open_framework(); - Impl_->Framework.set_window_title(title); - - WindowProperties windowProperties; - windowProperties.set_size(width, height); - windowProperties.set_title(title); - windowProperties.set_foreground(true); - - Impl_->WindowFrameworkHandle = Impl_->Framework.open_window(windowProperties, 0); - if (Impl_->WindowFrameworkHandle == nullptr) { + } catch (const std::bad_alloc&) { + MetaCoreWindowTrace("window:init exception bad_alloc"); + Shutdown(); + return false; + } catch (const std::exception& exceptionObject) { + MetaCoreWindowTrace("window:init exception std::exception"); + MetaCoreWindowTrace(exceptionObject.what()); + Shutdown(); + return false; + } catch (...) { + MetaCoreWindowTrace("window:init exception unknown"); Shutdown(); return false; } - - Impl_->GraphicsWindowHandle = Impl_->WindowFrameworkHandle->get_graphics_window(); - Impl_->NativeHandle = MetaCoreResolveNativeWindowHandle(Impl_->GraphicsWindowHandle); - if (Impl_->GraphicsWindowHandle == nullptr || Impl_->NativeHandle == nullptr) { - Shutdown(); - return false; - } - - MetaCoreGetWindowMap()[Impl_->NativeHandle] = Impl_.get(); - Impl_->OriginalWindowProc = reinterpret_cast( - SetWindowLongPtr(Impl_->NativeHandle, GWLP_WNDPROC, reinterpret_cast(&MetaCoreWindowSubclassProc)) - ); - - Impl_->CloseRequested = false; - Impl_->LastFrameTime = std::chrono::steady_clock::now(); - Impl_->Initialized = true; - return true; } void MetaCoreWindow::Shutdown() { @@ -212,7 +277,14 @@ void MetaCoreWindow::EndFrame() { } bool MetaCoreWindow::ShouldClose() const { - return !Impl_->Initialized || Impl_->CloseRequested; + if (!Impl_->Initialized) { + return true; + } + if (Impl_->CloseRequested) { + MetaCoreWindowTrace("window: should_close true (close requested)"); + return true; + } + return false; } void MetaCoreWindow::RequestClose() { diff --git a/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp b/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp index ed4b388..7df6213 100644 --- a/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp +++ b/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp @@ -3,17 +3,55 @@ #include "MetaCoreRender/MetaCoreRenderDevice.h" #include "MetaCoreScene/MetaCoreScene.h" +#include +#include +#include + namespace MetaCore { +namespace { + +void MetaCoreTrace(const char* message) { + if (message == nullptr) { + return; + } + + const auto now = std::chrono::system_clock::now(); + const auto time = std::chrono::system_clock::to_time_t(now); + struct tm timeInfo {}; + localtime_s(&timeInfo, &time); + + char timeBuffer[32]{}; + std::strftime(timeBuffer, sizeof(timeBuffer), "[%H:%M:%S] ", &timeInfo); + + FILE* file = nullptr; + if (fopen_s(&file, "editor.crash.log", "a") == 0 && file != nullptr) { + std::fputs(timeBuffer, file); + std::fputs(message, file); + std::fputs("\n", file); + std::fflush(file); + std::fclose(file); + } + + std::printf("%s%s\n", timeBuffer, message); +} + +} // namespace + bool MetaCoreEditorViewportRenderer::Initialize(MetaCoreRenderDevice& renderDevice) { + MetaCoreTrace("viewport_renderer:init enter"); Shutdown(); + MetaCoreTrace("viewport_renderer:init scene bridge begin"); if (!SceneBridge_.Initialize(renderDevice)) { + MetaCoreTrace("viewport_renderer:init scene bridge failed"); return false; } + MetaCoreTrace("viewport_renderer:init scene bridge done"); RenderDevice_ = &renderDevice; ViewportRect_ = MetaCoreViewportRect{}; + MetaCoreTrace("viewport_renderer:init success"); return true; } diff --git a/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp b/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp index f0b8c65..9ee6d1e 100644 --- a/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp +++ b/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp @@ -10,6 +10,7 @@ #include "directionalLight.h" #include "geom.h" #include "geomNode.h" +#include "geomLines.h" #include "geomTriangles.h" #include "geomVertexData.h" #include "geomVertexFormat.h" @@ -26,6 +27,9 @@ #include #include +#include +#include +#include #include #include #include @@ -34,6 +38,31 @@ namespace MetaCore { namespace { +void MetaCoreTrace(const char* message) { + if (message == nullptr) { + return; + } + + const auto now = std::chrono::system_clock::now(); + const auto time = std::chrono::system_clock::to_time_t(now); + struct tm timeInfo {}; + localtime_s(&timeInfo, &time); + + char timeBuffer[32]{}; + std::strftime(timeBuffer, sizeof(timeBuffer), "[%H:%M:%S] ", &timeInfo); + + FILE* file = nullptr; + if (fopen_s(&file, "editor.crash.log", "a") == 0 && file != nullptr) { + std::fputs(timeBuffer, file); + std::fputs(message, file); + std::fputs("\n", file); + std::fflush(file); + std::fclose(file); + } + + std::printf("%s%s\n", timeBuffer, message); +} + glm::mat4 MetaCoreBuildBasisSwapMatrix() { glm::mat4 basis(1.0F); basis[0] = glm::vec4(1.0F, 0.0F, 0.0F, 0.0F); @@ -66,9 +95,6 @@ LMatrix4f MetaCoreConvertTransformToPanda(const MetaCoreTransformComponent& tran } LPoint3f MetaCoreToPandaPoint(const glm::vec3& value) { - // MetaCore 使用右手系的 X 右 / Y 上 / Z 前。 - // Panda3D 使用右手系的 X 右 / Y 前 / Z 上。 - // 仅交换 Y/Z 会引入镜像,因此这里同时对前向轴取反,保持手性一致。 return LPoint3f(value.x, -value.z, value.y); } @@ -91,39 +117,105 @@ void MetaCoreApplyTransformToPandaNode(const MetaCoreTransformComponent& transfo } NodePath MetaCoreCreateGridNode(const NodePath& parentNode) { - LineSegs gridBuilder("MetaCoreGrid"); - gridBuilder.set_thickness(1.0F); + MetaCoreTrace("create_grid: begin"); + try { + MetaCoreTrace("create_grid: create vertex data"); + PT(GeomVertexData) vertexData = new GeomVertexData( + "MetaCoreGrid", + GeomVertexFormat::get_v3c4(), + Geom::UH_static + ); - constexpr int gridHalfExtent = 10; - for (int lineIndex = -gridHalfExtent; lineIndex <= gridHalfExtent; ++lineIndex) { - const bool isAxisLine = (lineIndex == 0); - gridBuilder.set_color(isAxisLine ? 0.42F : 0.30F, isAxisLine ? 0.45F : 0.33F, isAxisLine ? 0.50F : 0.36F, 1.0F); - gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast(lineIndex), 0.0F, static_cast(-gridHalfExtent)))); - gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast(lineIndex), 0.0F, static_cast(gridHalfExtent)))); - gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast(-gridHalfExtent), 0.0F, static_cast(lineIndex)))); - gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast(gridHalfExtent), 0.0F, static_cast(lineIndex)))); + GeomVertexWriter vertexWriter(vertexData, "vertex"); + GeomVertexWriter colorWriter(vertexData, "color"); + + MetaCoreTrace("create_grid: loop start"); + constexpr int gridHalfExtent = 10; + int vertexCount = 0; + for (int lineIndex = -gridHalfExtent; lineIndex <= gridHalfExtent; ++lineIndex) { + const bool isAxisLine = (lineIndex == 0); + const LColor color(isAxisLine ? 0.42F : 0.30F, isAxisLine ? 0.45F : 0.33F, isAxisLine ? 0.50F : 0.36F, 1.0F); + + // X-direction lines + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast(lineIndex), 0.0F, static_cast(-gridHalfExtent)))); + colorWriter.add_data4(color); + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast(lineIndex), 0.0F, static_cast(gridHalfExtent)))); + colorWriter.add_data4(color); + + // Z-direction lines + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast(-gridHalfExtent), 0.0F, static_cast(lineIndex)))); + colorWriter.add_data4(color); + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast(gridHalfExtent), 0.0F, static_cast(lineIndex)))); + colorWriter.add_data4(color); + + vertexCount += 4; + } + MetaCoreTrace("create_grid: loop end"); + + MetaCoreTrace("create_grid: create primitive"); + PT(GeomLines) lines = new GeomLines(Geom::UH_static); + for (int i = 0; i < vertexCount; i += 2) { + lines->add_vertices(i, i + 1); + } + + MetaCoreTrace("create_grid: create geom"); + PT(Geom) geom = new Geom(vertexData); + geom->add_primitive(lines.p()); + + PT(GeomNode) geomNode = new GeomNode("MetaCoreGridNode"); + geomNode->add_geom(geom); + + return parentNode.attach_new_node(geomNode); + } catch (...) { + return NodePath(); } - - return parentNode.attach_new_node(gridBuilder.create()); } NodePath MetaCoreCreateAxisNode(const NodePath& parentNode) { - LineSegs axisBuilder("MetaCoreAxis"); - axisBuilder.set_thickness(3.0F); + MetaCoreTrace("create_axis: begin"); + try { + PT(GeomVertexData) vertexData = new GeomVertexData( + "MetaCoreAxis", + GeomVertexFormat::get_v3c4(), + Geom::UH_static + ); - axisBuilder.set_color(0.92F, 0.26F, 0.26F, 1.0F); - axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); - axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(2.0F, 0.0F, 0.0F))); + GeomVertexWriter vertexWriter(vertexData, "vertex"); + GeomVertexWriter colorWriter(vertexData, "color"); - axisBuilder.set_color(0.28F, 0.86F, 0.36F, 1.0F); - axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); - axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 2.0F, 0.0F))); + // X Axis (Red) + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); + colorWriter.add_data4(LColor(0.92F, 0.26F, 0.26F, 1.0F)); + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(2.0F, 0.0F, 0.0F))); + colorWriter.add_data4(LColor(0.92F, 0.26F, 0.26F, 1.0F)); - axisBuilder.set_color(0.32F, 0.56F, 0.96F, 1.0F); - axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); - axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 2.0F))); + // Y Axis (Green) + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); + colorWriter.add_data4(LColor(0.28F, 0.86F, 0.36F, 1.0F)); + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 2.0F, 0.0F))); + colorWriter.add_data4(LColor(0.28F, 0.86F, 0.36F, 1.0F)); - return parentNode.attach_new_node(axisBuilder.create()); + // Z Axis (Blue) + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); + colorWriter.add_data4(LColor(0.32F, 0.56F, 0.96F, 1.0F)); + vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 2.0F))); + colorWriter.add_data4(LColor(0.32F, 0.56F, 0.96F, 1.0F)); + + PT(GeomLines) lines = new GeomLines(Geom::UH_static); + lines->add_vertices(0, 1); + lines->add_vertices(2, 3); + lines->add_vertices(4, 5); + + PT(Geom) geom = new Geom(vertexData); + geom->add_primitive(lines.p()); + + PT(GeomNode) geomNode = new GeomNode("MetaCoreAxisNode"); + geomNode->add_geom(geom); + + return parentNode.attach_new_node(geomNode); + } catch (...) { + return NodePath(); + } } NodePath MetaCoreCreateUnitCubeNode(const NodePath& parentNode) { @@ -196,7 +288,6 @@ glm::mat4 MetaCoreConvertPandaMatrixToGlm(const LMatrix4f& matrix) { glm::mat4 result(1.0F); for (int col = 0; col < 4; ++col) { for (int row = 0; row < 4; ++row) { - // Transpose mathematical matrix to switch from Panda's v*M to GLM's M*v. result[col][row] = matrix.get_cell(col, row); } } @@ -239,8 +330,10 @@ bool MetaCorePandaSceneBridge::Initialize(MetaCoreRenderDevice& renderDevice) { } Impl_->RenderDevice = &renderDevice; + Impl_->GridNode = MetaCoreCreateGridNode(*sceneRootHandle); Impl_->AxisNode = MetaCoreCreateAxisNode(*sceneRootHandle); + Impl_->GridNode.set_light_off(1); Impl_->AxisNode.set_light_off(1);