Stabilize editor startup and refactor scene interaction handling

This commit is contained in:
ayuan9957 2026-03-25 17:06:08 +08:00
parent 2ed3737c90
commit 79fe8fb906
6 changed files with 524 additions and 172 deletions

View File

@ -1,20 +1,126 @@
#include "MetaCoreEditor/MetaCoreEditorApp.h"
#include <csignal>
#include <cstdio>
#include <crtdbg.h>
#include <cstdlib>
#include <exception>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <new>
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: <non-null>");
}
if (functionName != nullptr) {
MetaCoreWriteCrashLog("function: <non-null>");
}
if (fileName != nullptr) {
MetaCoreWriteCrashLog("file: <non-null>");
}
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: <non-std exception>");
}
} else {
MetaCoreWriteCrashLog("exception: <none>");
}
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;
}

View File

@ -12,7 +12,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
if(MSVC)
# Debug 使Release 使 CRT
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
endif()
option(METACORE_BUILD_TESTS "Build MetaCore tests" ON)

View File

@ -16,6 +16,7 @@
#define GLM_ENABLE_EXPERIMENTAL
#include <cstdlib>
#include <cstdio>
#include <filesystem>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_transform.hpp>
@ -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<std::filesystem::path> 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<HWND>(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<MetaCoreEditorContext>(
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());

View File

@ -12,6 +12,10 @@
#include <windows.h>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <exception>
#include <string>
#include <unordered_map>
#include <memory>
#include <utility>
@ -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<WNDPROC>(
SetWindowLongPtr(Impl_->NativeHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&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<WNDPROC>(
SetWindowLongPtr(Impl_->NativeHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&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() {

View File

@ -3,17 +3,55 @@
#include "MetaCoreRender/MetaCoreRenderDevice.h"
#include "MetaCoreScene/MetaCoreScene.h"
#include <chrono>
#include <cstdio>
#include <ctime>
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;
}

View File

@ -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 <glm/gtx/euler_angles.hpp>
#include <glm/mat4x4.hpp>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <memory>
#include <unordered_map>
#include <unordered_set>
@ -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<float>(lineIndex), 0.0F, static_cast<float>(-gridHalfExtent))));
gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(lineIndex), 0.0F, static_cast<float>(gridHalfExtent))));
gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(-gridHalfExtent), 0.0F, static_cast<float>(lineIndex))));
gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(gridHalfExtent), 0.0F, static_cast<float>(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<float>(lineIndex), 0.0F, static_cast<float>(-gridHalfExtent))));
colorWriter.add_data4(color);
vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(lineIndex), 0.0F, static_cast<float>(gridHalfExtent))));
colorWriter.add_data4(color);
// Z-direction lines
vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(-gridHalfExtent), 0.0F, static_cast<float>(lineIndex))));
colorWriter.add_data4(color);
vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(gridHalfExtent), 0.0F, static_cast<float>(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);