Stabilize editor startup and refactor scene interaction handling
This commit is contained in:
parent
2ed3737c90
commit
79fe8fb906
@ -1,20 +1,126 @@
|
|||||||
#include "MetaCoreEditor/MetaCoreEditorApp.h"
|
#include "MetaCoreEditor/MetaCoreEditorApp.h"
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <exception>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <iostream>
|
#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[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
MetaCoreInstallDebugCrashHooks();
|
||||||
|
MetaCoreWriteCrashLogRaw("main: hooks installed");
|
||||||
if (argc > 0) {
|
if (argc > 0) {
|
||||||
|
MetaCoreWriteCrashLogRaw("main: set current_path begin");
|
||||||
std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path());
|
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;
|
MetaCore::MetaCoreEditorApp editorApp;
|
||||||
|
MetaCoreWriteCrashLogRaw("main: construct app done");
|
||||||
|
MetaCoreWriteCrashLogRaw("main: initialize begin");
|
||||||
if (!editorApp.Initialize()) {
|
if (!editorApp.Initialize()) {
|
||||||
|
MetaCoreWriteCrashLogRaw("main: initialize failed");
|
||||||
std::cerr << "MetaCoreEditorApp initialize failed\n";
|
std::cerr << "MetaCoreEditorApp initialize failed\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
MetaCoreWriteCrashLogRaw("main: initialize done");
|
||||||
|
|
||||||
|
MetaCoreWriteCrashLogRaw("main: run begin");
|
||||||
const int exitCode = editorApp.Run();
|
const int exitCode = editorApp.Run();
|
||||||
|
MetaCoreWriteCrashLogRaw("main: run done");
|
||||||
editorApp.Shutdown();
|
editorApp.Shutdown();
|
||||||
|
MetaCoreWriteCrashLogRaw("main: shutdown done");
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# Debug 使用调试运行库,Release 使用可分发运行库,避免不同配置之间的 CRT 冲突。
|
# Debug 使用调试运行库,Release 使用可分发运行库,避免不同配置之间的 CRT 冲突。
|
||||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(METACORE_BUILD_TESTS "Build MetaCore tests" ON)
|
option(METACORE_BUILD_TESTS "Build MetaCore tests" ON)
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <glm/ext/matrix_clip_space.hpp>
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
@ -35,6 +36,29 @@ namespace MetaCore {
|
|||||||
|
|
||||||
namespace {
|
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() {
|
void MetaCoreApplyEditorStyle() {
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
@ -62,6 +86,7 @@ void MetaCoreConfigureChineseFont() {
|
|||||||
io.Fonts->AddFontDefault();
|
io.Fonts->AddFontDefault();
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
#if !defined(_DEBUG)
|
||||||
std::vector<std::filesystem::path> candidatePaths;
|
std::vector<std::filesystem::path> candidatePaths;
|
||||||
char* windowsDirectory = nullptr;
|
char* windowsDirectory = nullptr;
|
||||||
std::size_t windowsDirectoryLength = 0;
|
std::size_t windowsDirectoryLength = 0;
|
||||||
@ -75,19 +100,26 @@ void MetaCoreConfigureChineseFont() {
|
|||||||
|
|
||||||
for (const auto& candidatePath : candidatePaths) {
|
for (const auto& candidatePath : candidatePaths) {
|
||||||
if (std::filesystem::exists(candidatePath)) {
|
if (std::filesystem::exists(candidatePath)) {
|
||||||
ImFont* chineseFont = io.Fonts->AddFontFromFileTTF(
|
try {
|
||||||
candidatePath.string().c_str(),
|
// ChineseFull glyph range may allocate a very large atlas in Debug builds.
|
||||||
18.0F,
|
// Use Common range for stability; fallback to default font if allocation fails.
|
||||||
nullptr,
|
ImFont* chineseFont = io.Fonts->AddFontFromFileTTF(
|
||||||
io.Fonts->GetGlyphRangesChineseFull()
|
candidatePath.string().c_str(),
|
||||||
);
|
17.0F,
|
||||||
if (chineseFont != nullptr) {
|
nullptr,
|
||||||
io.FontDefault = chineseFont;
|
io.Fonts->GetGlyphRangesChineseSimplifiedCommon()
|
||||||
|
);
|
||||||
|
if (chineseFont != nullptr) {
|
||||||
|
io.FontDefault = chineseFont;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (const std::bad_alloc&) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 MetaCoreBuildTransformMatrix(const MetaCoreTransformComponent& transform) {
|
glm::mat4 MetaCoreBuildTransformMatrix(const MetaCoreTransformComponent& transform) {
|
||||||
@ -179,14 +211,19 @@ MetaCoreEditorApp::~MetaCoreEditorApp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreEditorApp::Initialize() {
|
bool MetaCoreEditorApp::Initialize() {
|
||||||
|
MetaCoreTraceStartup("init: begin");
|
||||||
if (Initialized_) {
|
if (Initialized_) {
|
||||||
|
MetaCoreTraceStartup("init: already initialized");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: window");
|
||||||
if (!Window_.Initialize(1600, 900, "MetaCore Editor")) {
|
if (!Window_.Initialize(1600, 900, "MetaCore Editor")) {
|
||||||
|
MetaCoreTraceStartup("init: window failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: message handler");
|
||||||
Window_.SetNativeWindowMessageHandler([](void* nativeWindowHandle, unsigned int message, std::uintptr_t wparam, std::intptr_t lparam) {
|
Window_.SetNativeWindowMessageHandler([](void* nativeWindowHandle, unsigned int message, std::uintptr_t wparam, std::intptr_t lparam) {
|
||||||
return ImGui_ImplWin32_WndProcHandler(
|
return ImGui_ImplWin32_WndProcHandler(
|
||||||
static_cast<HWND>(nativeWindowHandle),
|
static_cast<HWND>(nativeWindowHandle),
|
||||||
@ -196,24 +233,34 @@ bool MetaCoreEditorApp::Initialize() {
|
|||||||
) != 0;
|
) != 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: render device");
|
||||||
if (!RenderDevice_.Initialize(Window_)) {
|
if (!RenderDevice_.Initialize(Window_)) {
|
||||||
|
MetaCoreTraceStartup("init: render device failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: imgui");
|
||||||
if (!InitializeImGui()) {
|
if (!InitializeImGui()) {
|
||||||
|
MetaCoreTraceStartup("init: imgui failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: viewport renderer");
|
||||||
if (!ViewportRenderer_.Initialize(RenderDevice_)) {
|
if (!ViewportRenderer_.Initialize(RenderDevice_)) {
|
||||||
|
MetaCoreTraceStartup("init: viewport renderer failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: create default scene");
|
||||||
Scene_ = MetaCoreCreateDefaultScene();
|
Scene_ = MetaCoreCreateDefaultScene();
|
||||||
|
MetaCoreTraceStartup("init: create modules");
|
||||||
Modules_.push_back(MetaCoreCreateBuiltinEditorModule());
|
Modules_.push_back(MetaCoreCreateBuiltinEditorModule());
|
||||||
|
MetaCoreTraceStartup("init: startup modules");
|
||||||
for (const auto& module : Modules_) {
|
for (const auto& module : Modules_) {
|
||||||
module->Startup(ModuleRegistry_);
|
module->Startup(ModuleRegistry_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: create editor context");
|
||||||
EditorContext_ = std::make_unique<MetaCoreEditorContext>(
|
EditorContext_ = std::make_unique<MetaCoreEditorContext>(
|
||||||
Window_,
|
Window_,
|
||||||
RenderDevice_,
|
RenderDevice_,
|
||||||
@ -223,6 +270,7 @@ bool MetaCoreEditorApp::Initialize() {
|
|||||||
ModuleRegistry_
|
ModuleRegistry_
|
||||||
);
|
);
|
||||||
|
|
||||||
|
MetaCoreTraceStartup("init: select default cube");
|
||||||
for (const MetaCoreGameObject& object : Scene_.GetGameObjects()) {
|
for (const MetaCoreGameObject& object : Scene_.GetGameObjects()) {
|
||||||
if (object.Name == "Cube") {
|
if (object.Name == "Cube") {
|
||||||
EditorContext_->SetSelectedObjectId(object.Id);
|
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, "System", "MetaCore 编辑器已初始化");
|
||||||
EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Render", "Panda3D 场景视口已准备完成");
|
EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Render", "Panda3D 场景视口已准备完成");
|
||||||
|
|
||||||
Initialized_ = true;
|
Initialized_ = true;
|
||||||
|
MetaCoreTraceStartup("init: done");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MetaCoreEditorApp::Run() {
|
int MetaCoreEditorApp::Run() {
|
||||||
|
MetaCoreTraceStartup("main: run loop enter");
|
||||||
while (!Window_.ShouldClose()) {
|
while (!Window_.ShouldClose()) {
|
||||||
Window_.BeginFrame();
|
Window_.BeginFrame();
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
ImGui_ImplWin32_NewFrame();
|
ImGui_ImplWin32_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
ImGuizmo::BeginFrame();
|
if (GMetaCoreEnableImGuizmo) {
|
||||||
|
ImGuizmo::BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
DrawEditorFrame();
|
DrawEditorFrame();
|
||||||
|
|
||||||
@ -277,21 +330,35 @@ void MetaCoreEditorApp::Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreEditorApp::InitializeImGui() {
|
bool MetaCoreEditorApp::InitializeImGui() {
|
||||||
|
MetaCoreTraceStartup("imgui: begin");
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
|
MetaCoreTraceStartup("imgui: context created");
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
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();
|
MetaCoreConfigureChineseFont();
|
||||||
|
MetaCoreTraceStartup("imgui: configure font done");
|
||||||
MetaCoreApplyEditorStyle();
|
MetaCoreApplyEditorStyle();
|
||||||
|
MetaCoreTraceStartup("imgui: style done");
|
||||||
|
|
||||||
if (!ImGui_ImplWin32_InitForOpenGL(Window_.GetNativeWindowHandle())) {
|
if (!ImGui_ImplWin32_InitForOpenGL(Window_.GetNativeWindowHandle())) {
|
||||||
|
MetaCoreTraceStartup("imgui: win32 init failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
MetaCoreTraceStartup("imgui: win32 init done");
|
||||||
|
|
||||||
if (!ImGui_ImplOpenGL3_Init("#version 130")) {
|
if (!ImGui_ImplOpenGL3_Init("#version 130")) {
|
||||||
|
MetaCoreTraceStartup("imgui: opengl3 init failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
MetaCoreTraceStartup("imgui: opengl3 init done");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -433,117 +500,93 @@ void MetaCoreEditorApp::DrawEditorFrame() {
|
|||||||
bool gizmoHovering = false;
|
bool gizmoHovering = false;
|
||||||
bool gizmoUsing = false;
|
bool gizmoUsing = false;
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(ImVec2(centralNode->Pos.x, centralNode->Pos.y + sceneToolbarHeight));
|
if (GMetaCoreEnableImGuizmo) {
|
||||||
ImGui::SetNextWindowSize(ImVec2(viewportState.Width, viewportState.Height));
|
ImGui::SetNextWindowPos(ImVec2(centralNode->Pos.x, centralNode->Pos.y + sceneToolbarHeight));
|
||||||
ImGui::SetNextWindowBgAlpha(0.0F);
|
ImGui::SetNextWindowSize(ImVec2(viewportState.Width, viewportState.Height));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F);
|
ImGui::SetNextWindowBgAlpha(0.0F);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0F, 0.0F));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0F, 0.0F));
|
||||||
|
|
||||||
constexpr ImGuiWindowFlags gizmoCanvasFlags =
|
constexpr ImGuiWindowFlags gizmoCanvasFlags =
|
||||||
ImGuiWindowFlags_NoDecoration |
|
ImGuiWindowFlags_NoDecoration |
|
||||||
ImGuiWindowFlags_NoDocking |
|
ImGuiWindowFlags_NoDocking |
|
||||||
ImGuiWindowFlags_NoMove |
|
ImGuiWindowFlags_NoMove |
|
||||||
ImGuiWindowFlags_NoSavedSettings |
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
ImGuiWindowFlags_NoBringToFrontOnFocus |
|
ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||||
ImGuiWindowFlags_NoNavFocus |
|
ImGuiWindowFlags_NoNavFocus |
|
||||||
ImGuiWindowFlags_NoBackground |
|
ImGuiWindowFlags_NoBackground |
|
||||||
ImGuiWindowFlags_NoInputs;
|
ImGuiWindowFlags_NoInputs;
|
||||||
|
|
||||||
bool gizmoCanvasOpen = true;
|
bool gizmoCanvasOpen = true;
|
||||||
ImGui::Begin("MetaCoreSceneGizmoCanvas", &gizmoCanvasOpen, gizmoCanvasFlags);
|
ImGui::Begin("MetaCoreSceneGizmoCanvas", &gizmoCanvasOpen, gizmoCanvasFlags);
|
||||||
|
|
||||||
// Guard against degenerate camera and aspect ratio.
|
const float cameraDistance = glm::distance(sceneView.CameraPosition, sceneView.CameraTarget);
|
||||||
const float cameraDistance = glm::distance(sceneView.CameraPosition, sceneView.CameraTarget);
|
const float gizmoAspect = viewportState.Width / viewportState.Height;
|
||||||
const float gizmoAspect = viewportState.Width / viewportState.Height;
|
|
||||||
|
|
||||||
MetaCoreGameObject* selectedObject = EditorContext_->GetSelectedGameObject();
|
MetaCoreGameObject* selectedObject = EditorContext_->GetSelectedGameObject();
|
||||||
if (selectedObject != nullptr &&
|
if (selectedObject != nullptr &&
|
||||||
EditorContext_->GetGizmoOperation() != MetaCoreGizmoOperation::None &&
|
EditorContext_->GetGizmoOperation() != MetaCoreGizmoOperation::None &&
|
||||||
cameraDistance >= 0.001F &&
|
cameraDistance >= 0.001F &&
|
||||||
gizmoAspect >= 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.
|
glm::mat4 transformMatrix = MetaCoreBuildPandaSpaceTransformMatrix(selectedObject->Transform);
|
||||||
// MetaCoreConvertPandaMatrixToGlm correctly handles Panda row-major→GLM column-major.
|
(void)ViewportRenderer_.TryGetObjectWorldMatrix(selectedObject->Id, transformMatrix);
|
||||||
// TryGetEditorCameraMatrices returns:
|
const glm::mat4 originalTransformMatrix = transformMatrix;
|
||||||
// viewMatrix = inverse(EditorCamera.get_mat(SceneRoot))
|
|
||||||
// projectionMatrix = lens->get_projection_mat()
|
ImGuizmo::SetOrthographic(false);
|
||||||
glm::mat4 gizmoViewMatrix(1.0F);
|
ImGuizmo::Enable(true);
|
||||||
glm::mat4 gizmoProjectionMatrix(1.0F);
|
ImGuizmo::AllowAxisFlip(true);
|
||||||
if (!RenderDevice_.TryGetEditorCameraMatrices(gizmoViewMatrix, gizmoProjectionMatrix)) {
|
ImGuizmo::SetGizmoSizeClipSpace(0.30F);
|
||||||
gizmoProjectionMatrix = glm::perspective(
|
ImGuizmo::SetDrawlist(ImGui::GetWindowDrawList());
|
||||||
glm::radians(sceneView.VerticalFieldOfViewDegrees),
|
ImGuizmo::SetRect(
|
||||||
gizmoAspect, 0.05F, 500.0F
|
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.
|
gizmoHovering = ImGuizmo::IsOver();
|
||||||
glm::mat4 transformMatrix = MetaCoreBuildPandaSpaceTransformMatrix(selectedObject->Transform);
|
gizmoUsing = ImGuizmo::IsUsing();
|
||||||
(void)ViewportRenderer_.TryGetObjectWorldMatrix(selectedObject->Id, transformMatrix);
|
SceneInteractionService_.HandleGizmoBeginUse(*EditorContext_, gizmoUsing);
|
||||||
const glm::mat4 originalTransformMatrix = transformMatrix;
|
if (gizmoUsing) {
|
||||||
|
switch (EditorContext_->GetGizmoOperation()) {
|
||||||
ImGuizmo::SetOrthographic(false);
|
case MetaCoreGizmoOperation::Translate:
|
||||||
ImGuizmo::Enable(true);
|
MetaCoreApplyTranslationFromPandaSpaceMatrix(transformMatrix, selectedObject->Transform);
|
||||||
ImGuizmo::AllowAxisFlip(true);
|
break;
|
||||||
ImGuizmo::SetGizmoSizeClipSpace(0.30F);
|
case MetaCoreGizmoOperation::Rotate:
|
||||||
ImGuizmo::SetDrawlist(ImGui::GetWindowDrawList());
|
case MetaCoreGizmoOperation::Scale:
|
||||||
ImGuizmo::SetRect(
|
MetaCoreApplyTransformFromPandaSpaceMatrix(transformMatrix, selectedObject->Transform);
|
||||||
ImGui::GetWindowPos().x,
|
break;
|
||||||
ImGui::GetWindowPos().y,
|
case MetaCoreGizmoOperation::None:
|
||||||
viewportState.Width,
|
default:
|
||||||
viewportState.Height
|
transformMatrix = originalTransformMatrix;
|
||||||
);
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr float viewManipulateSize = 112.0F;
|
ImGui::End();
|
||||||
const ImVec2 canvasPosition = ImGui::GetWindowPos();
|
ImGui::PopStyleVar(3);
|
||||||
ImGuizmo::ViewManipulate(
|
} else {
|
||||||
glm::value_ptr(gizmoViewMatrix),
|
gizmoHovering = false;
|
||||||
cameraDistance,
|
gizmoUsing = false;
|
||||||
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);
|
|
||||||
|
|
||||||
if (!gizmoUsing) {
|
if (!gizmoUsing) {
|
||||||
EditorContext_->GetCameraController().Update(viewportState, EditorContext_->GetInput());
|
EditorContext_->GetCameraController().Update(viewportState, EditorContext_->GetInput());
|
||||||
|
|||||||
@ -12,6 +12,10 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -20,6 +24,31 @@ namespace MetaCore {
|
|||||||
|
|
||||||
namespace {
|
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) {
|
void MetaCoreConfigurePanda3D(const std::string& title) {
|
||||||
static bool configured = false;
|
static bool configured = false;
|
||||||
if (configured) {
|
if (configured) {
|
||||||
@ -34,7 +63,11 @@ void MetaCoreConfigurePanda3D(const std::string& title) {
|
|||||||
load_prc_file_data("", "notify-level warning\n");
|
load_prc_file_data("", "notify-level warning\n");
|
||||||
load_prc_file_data("", "audio-library-name null\n");
|
load_prc_file_data("", "audio-library-name null\n");
|
||||||
load_prc_file_data("", "textures-power-2 none\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;
|
configured = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,41 +149,73 @@ MetaCoreWindow::~MetaCoreWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreWindow::Initialize(int width, int height, const std::string& title) {
|
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;
|
return true;
|
||||||
}
|
} catch (const std::bad_alloc&) {
|
||||||
|
MetaCoreWindowTrace("window:init exception bad_alloc");
|
||||||
MetaCoreConfigurePanda3D(title);
|
Shutdown();
|
||||||
Impl_->Framework.open_framework();
|
return false;
|
||||||
Impl_->Framework.set_window_title(title);
|
} catch (const std::exception& exceptionObject) {
|
||||||
|
MetaCoreWindowTrace("window:init exception std::exception");
|
||||||
WindowProperties windowProperties;
|
MetaCoreWindowTrace(exceptionObject.what());
|
||||||
windowProperties.set_size(width, height);
|
Shutdown();
|
||||||
windowProperties.set_title(title);
|
return false;
|
||||||
windowProperties.set_foreground(true);
|
} catch (...) {
|
||||||
|
MetaCoreWindowTrace("window:init exception unknown");
|
||||||
Impl_->WindowFrameworkHandle = Impl_->Framework.open_window(windowProperties, 0);
|
|
||||||
if (Impl_->WindowFrameworkHandle == nullptr) {
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
return false;
|
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() {
|
void MetaCoreWindow::Shutdown() {
|
||||||
@ -212,7 +277,14 @@ void MetaCoreWindow::EndFrame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreWindow::ShouldClose() const {
|
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() {
|
void MetaCoreWindow::RequestClose() {
|
||||||
|
|||||||
@ -3,17 +3,55 @@
|
|||||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||||
#include "MetaCoreScene/MetaCoreScene.h"
|
#include "MetaCoreScene/MetaCoreScene.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
namespace MetaCore {
|
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) {
|
bool MetaCoreEditorViewportRenderer::Initialize(MetaCoreRenderDevice& renderDevice) {
|
||||||
|
MetaCoreTrace("viewport_renderer:init enter");
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
|
||||||
|
MetaCoreTrace("viewport_renderer:init scene bridge begin");
|
||||||
if (!SceneBridge_.Initialize(renderDevice)) {
|
if (!SceneBridge_.Initialize(renderDevice)) {
|
||||||
|
MetaCoreTrace("viewport_renderer:init scene bridge failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
MetaCoreTrace("viewport_renderer:init scene bridge done");
|
||||||
|
|
||||||
RenderDevice_ = &renderDevice;
|
RenderDevice_ = &renderDevice;
|
||||||
ViewportRect_ = MetaCoreViewportRect{};
|
ViewportRect_ = MetaCoreViewportRect{};
|
||||||
|
MetaCoreTrace("viewport_renderer:init success");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include "directionalLight.h"
|
#include "directionalLight.h"
|
||||||
#include "geom.h"
|
#include "geom.h"
|
||||||
#include "geomNode.h"
|
#include "geomNode.h"
|
||||||
|
#include "geomLines.h"
|
||||||
#include "geomTriangles.h"
|
#include "geomTriangles.h"
|
||||||
#include "geomVertexData.h"
|
#include "geomVertexData.h"
|
||||||
#include "geomVertexFormat.h"
|
#include "geomVertexFormat.h"
|
||||||
@ -26,6 +27,9 @@
|
|||||||
#include <glm/gtx/euler_angles.hpp>
|
#include <glm/gtx/euler_angles.hpp>
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -34,6 +38,31 @@ namespace MetaCore {
|
|||||||
|
|
||||||
namespace {
|
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 MetaCoreBuildBasisSwapMatrix() {
|
||||||
glm::mat4 basis(1.0F);
|
glm::mat4 basis(1.0F);
|
||||||
basis[0] = glm::vec4(1.0F, 0.0F, 0.0F, 0.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) {
|
LPoint3f MetaCoreToPandaPoint(const glm::vec3& value) {
|
||||||
// MetaCore 使用右手系的 X 右 / Y 上 / Z 前。
|
|
||||||
// Panda3D 使用右手系的 X 右 / Y 前 / Z 上。
|
|
||||||
// 仅交换 Y/Z 会引入镜像,因此这里同时对前向轴取反,保持手性一致。
|
|
||||||
return LPoint3f(value.x, -value.z, value.y);
|
return LPoint3f(value.x, -value.z, value.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,39 +117,105 @@ void MetaCoreApplyTransformToPandaNode(const MetaCoreTransformComponent& transfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
NodePath MetaCoreCreateGridNode(const NodePath& parentNode) {
|
NodePath MetaCoreCreateGridNode(const NodePath& parentNode) {
|
||||||
LineSegs gridBuilder("MetaCoreGrid");
|
MetaCoreTrace("create_grid: begin");
|
||||||
gridBuilder.set_thickness(1.0F);
|
try {
|
||||||
|
MetaCoreTrace("create_grid: create vertex data");
|
||||||
|
PT(GeomVertexData) vertexData = new GeomVertexData(
|
||||||
|
"MetaCoreGrid",
|
||||||
|
GeomVertexFormat::get_v3c4(),
|
||||||
|
Geom::UH_static
|
||||||
|
);
|
||||||
|
|
||||||
constexpr int gridHalfExtent = 10;
|
GeomVertexWriter vertexWriter(vertexData, "vertex");
|
||||||
for (int lineIndex = -gridHalfExtent; lineIndex <= gridHalfExtent; ++lineIndex) {
|
GeomVertexWriter colorWriter(vertexData, "color");
|
||||||
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);
|
MetaCoreTrace("create_grid: loop start");
|
||||||
gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(lineIndex), 0.0F, static_cast<float>(-gridHalfExtent))));
|
constexpr int gridHalfExtent = 10;
|
||||||
gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(lineIndex), 0.0F, static_cast<float>(gridHalfExtent))));
|
int vertexCount = 0;
|
||||||
gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(-gridHalfExtent), 0.0F, static_cast<float>(lineIndex))));
|
for (int lineIndex = -gridHalfExtent; lineIndex <= gridHalfExtent; ++lineIndex) {
|
||||||
gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(gridHalfExtent), 0.0F, static_cast<float>(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) {
|
NodePath MetaCoreCreateAxisNode(const NodePath& parentNode) {
|
||||||
LineSegs axisBuilder("MetaCoreAxis");
|
MetaCoreTrace("create_axis: begin");
|
||||||
axisBuilder.set_thickness(3.0F);
|
try {
|
||||||
|
PT(GeomVertexData) vertexData = new GeomVertexData(
|
||||||
|
"MetaCoreAxis",
|
||||||
|
GeomVertexFormat::get_v3c4(),
|
||||||
|
Geom::UH_static
|
||||||
|
);
|
||||||
|
|
||||||
axisBuilder.set_color(0.92F, 0.26F, 0.26F, 1.0F);
|
GeomVertexWriter vertexWriter(vertexData, "vertex");
|
||||||
axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F)));
|
GeomVertexWriter colorWriter(vertexData, "color");
|
||||||
axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(2.0F, 0.0F, 0.0F)));
|
|
||||||
|
|
||||||
axisBuilder.set_color(0.28F, 0.86F, 0.36F, 1.0F);
|
// X Axis (Red)
|
||||||
axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F)));
|
vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F)));
|
||||||
axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 2.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);
|
// Y Axis (Green)
|
||||||
axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F)));
|
vertexWriter.add_data3(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F)));
|
||||||
axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 2.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) {
|
NodePath MetaCoreCreateUnitCubeNode(const NodePath& parentNode) {
|
||||||
@ -196,7 +288,6 @@ glm::mat4 MetaCoreConvertPandaMatrixToGlm(const LMatrix4f& matrix) {
|
|||||||
glm::mat4 result(1.0F);
|
glm::mat4 result(1.0F);
|
||||||
for (int col = 0; col < 4; ++col) {
|
for (int col = 0; col < 4; ++col) {
|
||||||
for (int row = 0; row < 4; ++row) {
|
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);
|
result[col][row] = matrix.get_cell(col, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,8 +330,10 @@ bool MetaCorePandaSceneBridge::Initialize(MetaCoreRenderDevice& renderDevice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Impl_->RenderDevice = &renderDevice;
|
Impl_->RenderDevice = &renderDevice;
|
||||||
|
|
||||||
Impl_->GridNode = MetaCoreCreateGridNode(*sceneRootHandle);
|
Impl_->GridNode = MetaCoreCreateGridNode(*sceneRootHandle);
|
||||||
Impl_->AxisNode = MetaCoreCreateAxisNode(*sceneRootHandle);
|
Impl_->AxisNode = MetaCoreCreateAxisNode(*sceneRootHandle);
|
||||||
|
|
||||||
Impl_->GridNode.set_light_off(1);
|
Impl_->GridNode.set_light_off(1);
|
||||||
Impl_->AxisNode.set_light_off(1);
|
Impl_->AxisNode.set_light_off(1);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user