diff --git a/.gitignore b/.gitignore index 4129747..4d01460 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ build/ vcpkg_installed/ downloads/ +.metacore/ .vs/ CMakeUserPresets.json imgui.ini diff --git a/Apps/MetaCoreEditor/main.cpp b/Apps/MetaCoreEditor/main.cpp index 2446133..654171b 100644 --- a/Apps/MetaCoreEditor/main.cpp +++ b/Apps/MetaCoreEditor/main.cpp @@ -1,8 +1,16 @@ #include "MetaCoreEditor/MetaCoreEditorApp.h" -int main() { +#include +#include + +int main(int argc, char* argv[]) { + if (argc > 0) { + std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path()); + } + MetaCore::MetaCoreEditorApp editorApp; if (!editorApp.Initialize()) { + std::cerr << "MetaCoreEditorApp initialize failed\n"; return 1; } diff --git a/Apps/MetaCorePlayer/main.cpp b/Apps/MetaCorePlayer/main.cpp index 4c1e56e..395e3be 100644 --- a/Apps/MetaCorePlayer/main.cpp +++ b/Apps/MetaCorePlayer/main.cpp @@ -1,6 +1,67 @@ +#include "MetaCorePlatform/MetaCoreWindow.h" +#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h" +#include "MetaCoreRender/MetaCoreRenderDevice.h" +#include "MetaCoreRender/MetaCoreRenderTypes.h" +#include "MetaCoreScene/MetaCoreScene.h" + +#include #include -int main() { - std::cout << "MetaCorePlayer 目前保留为后续运行时模块接入入口。\n"; +namespace { + +MetaCore::MetaCoreSceneView MetaCoreBuildPlayerSceneView() { + MetaCore::MetaCoreSceneView sceneView; + sceneView.CameraPosition = {0.0F, 2.5F, 6.5F}; + sceneView.CameraTarget = {0.0F, 0.7F, 0.0F}; + sceneView.CameraUp = {0.0F, 1.0F, 0.0F}; + sceneView.VerticalFieldOfViewDegrees = 60.0F; + return sceneView; +} + +} // namespace + +int main(int argc, char* argv[]) { + if (argc > 0) { + std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path()); + } + + MetaCore::MetaCoreWindow window; + if (!window.Initialize(1280, 720, "MetaCore Player")) { + std::cerr << "MetaCorePlayer: window initialize failed\n"; + return 1; + } + + MetaCore::MetaCoreRenderDevice renderDevice; + if (!renderDevice.Initialize(window)) { + std::cerr << "MetaCorePlayer: render device initialize failed\n"; + return 1; + } + + MetaCore::MetaCoreEditorViewportRenderer viewportRenderer; + if (!viewportRenderer.Initialize(renderDevice)) { + std::cerr << "MetaCorePlayer: viewport renderer initialize failed\n"; + return 1; + } + + MetaCore::MetaCoreScene scene = MetaCore::MetaCoreCreateDefaultScene(); + + while (!window.ShouldClose()) { + window.BeginFrame(); + const auto [windowWidth, windowHeight] = window.GetWindowSize(); + viewportRenderer.SetViewportRect(MetaCore::MetaCoreViewportRect{ + 0.0F, + 0.0F, + static_cast(windowWidth), + static_cast(windowHeight) + }); + viewportRenderer.RenderSceneToViewport(scene, MetaCoreBuildPlayerSceneView()); + renderDevice.RenderFrame(); + renderDevice.PresentFrame(); + window.EndFrame(); + } + + viewportRenderer.Shutdown(); + renderDevice.Shutdown(); + window.Shutdown(); return 0; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 375e8f1..e7b25d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.26) project(MetaCore VERSION 1.0.0 - DESCRIPTION "MetaCore Unity-like editor prototype" + DESCRIPTION "MetaCore Panda3D-based Unity-like editor prototype" LANGUAGES CXX ) @@ -10,27 +10,23 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -option(METACORE_BUILD_TESTS "Build MetaCore tests" ON) +if(MSVC) + # Debug 使用调试运行库,Release 使用可分发运行库,避免不同配置之间的 CRT 冲突。 + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") +endif() -if(EXISTS "${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-windows/share/glad/gladConfig.cmake") +option(METACORE_BUILD_TESTS "Build MetaCore tests" ON) +option(METACORE_AUTO_PREPARE_PANDA3D "Automatically prepare Panda3D SDK during configure" ON) + +list(PREPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + +if(EXISTS "${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-windows/share/imgui/imgui-config.cmake") list(PREPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-windows") endif() -set(METACORE_RUNTIME_BIN_DIR "${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-windows/bin") +include(MetaCorePanda3D) +metacore_prepare_panda3d() -function(metacore_copy_runtime_dlls target_name) - if(EXISTS "${METACORE_RUNTIME_BIN_DIR}/glfw3.dll") - add_custom_command(TARGET ${target_name} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${METACORE_RUNTIME_BIN_DIR}/glfw3.dll" - "$" - ) - endif() -endfunction() - -find_package(OpenGL REQUIRED) -find_package(glad CONFIG REQUIRED) -find_package(glfw3 CONFIG REQUIRED) find_package(glm CONFIG REQUIRED) find_package(imgui CONFIG REQUIRED) @@ -54,12 +50,15 @@ target_include_directories(MetaCoreFoundation Source/MetaCoreFoundation/Public ) +set(METACORE_COMMON_WARNINGS) if(MSVC) - target_compile_options(MetaCoreFoundation PRIVATE /W4 /permissive- /EHsc) + set(METACORE_COMMON_WARNINGS /W4 /permissive- /EHsc) else() - target_compile_options(MetaCoreFoundation PRIVATE -Wall -Wextra -Wpedantic) + set(METACORE_COMMON_WARNINGS -Wall -Wextra -Wpedantic) endif() +target_compile_options(MetaCoreFoundation PRIVATE ${METACORE_COMMON_WARNINGS}) + set(METACORE_PLATFORM_HEADERS Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreInput.h Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreWindow.h @@ -83,14 +82,12 @@ target_include_directories(MetaCorePlatform target_link_libraries(MetaCorePlatform PUBLIC MetaCoreFoundation - glfw + MetaCorePanda3D::SDK + glm::glm ) -if(MSVC) - target_compile_options(MetaCorePlatform PRIVATE /W4 /permissive- /EHsc) -else() - target_compile_options(MetaCorePlatform PRIVATE -Wall -Wextra -Wpedantic) -endif() +target_compile_options(MetaCorePlatform PRIVATE ${METACORE_COMMON_WARNINGS}) +target_compile_definitions(MetaCorePlatform PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) set(METACORE_SCENE_HEADERS Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreComponents.h @@ -118,29 +115,19 @@ target_link_libraries(MetaCoreScene glm::glm ) -if(MSVC) - target_compile_options(MetaCoreScene PRIVATE /W4 /permissive- /EHsc) -else() - target_compile_options(MetaCoreScene PRIVATE -Wall -Wextra -Wpedantic) -endif() +target_compile_options(MetaCoreScene PRIVATE ${METACORE_COMMON_WARNINGS}) set(METACORE_RENDER_HEADERS - Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h - Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreShaderProgram.h - Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreMesh.h - Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreDebugGeometry.h - Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h - Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreSceneRenderer.h Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreEditorViewportRenderer.h + Source/MetaCoreRender/Public/MetaCoreRender/MetaCorePandaSceneBridge.h + Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h + Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h ) set(METACORE_RENDER_SOURCES - Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp - Source/MetaCoreRender/Private/MetaCoreShaderProgram.cpp - Source/MetaCoreRender/Private/MetaCoreMesh.cpp - Source/MetaCoreRender/Private/MetaCoreDebugGeometry.cpp - Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp + Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp + Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp ) add_library(MetaCoreRender STATIC @@ -156,35 +143,31 @@ target_include_directories(MetaCoreRender target_link_libraries(MetaCoreRender PUBLIC MetaCoreFoundation - MetaCoreScene MetaCorePlatform - OpenGL::GL - glad::glad + MetaCoreScene + MetaCorePanda3D::SDK glm::glm ) -if(MSVC) - target_compile_options(MetaCoreRender PRIVATE /W4 /permissive- /EHsc) -else() - target_compile_options(MetaCoreRender PRIVATE -Wall -Wextra -Wpedantic) -endif() +target_compile_options(MetaCoreRender PRIVATE ${METACORE_COMMON_WARNINGS}) set(METACORE_EDITOR_HEADERS - Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h - Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorApp.h + Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h + Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h ) set(METACORE_EDITOR_PRIVATE_HEADERS + Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.h Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.h ) set(METACORE_EDITOR_SOURCES - Source/MetaCoreEditor/Private/MetaCoreEditorModule.cpp - Source/MetaCoreEditor/Private/MetaCoreEditorContext.cpp - Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.cpp Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp + Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.cpp + Source/MetaCoreEditor/Private/MetaCoreEditorContext.cpp + Source/MetaCoreEditor/Private/MetaCoreEditorModule.cpp ) add_library(MetaCoreEditor STATIC @@ -204,17 +187,14 @@ target_link_libraries(MetaCoreEditor PUBLIC MetaCoreFoundation MetaCorePlatform - MetaCoreScene MetaCoreRender + MetaCoreScene glm::glm imgui::imgui ) -if(MSVC) - target_compile_options(MetaCoreEditor PRIVATE /W4 /permissive- /EHsc) -else() - target_compile_options(MetaCoreEditor PRIVATE -Wall -Wextra -Wpedantic) -endif() +target_compile_options(MetaCoreEditor PRIVATE ${METACORE_COMMON_WARNINGS}) +target_compile_definitions(MetaCoreEditor PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) add_executable(MetaCoreEditorApp Apps/MetaCoreEditor/main.cpp @@ -224,7 +204,8 @@ target_link_libraries(MetaCoreEditorApp PRIVATE MetaCoreEditor ) -metacore_copy_runtime_dlls(MetaCoreEditorApp) + +metacore_stage_panda3d_runtime(MetaCoreEditorApp) add_executable(MetaCorePlayer Apps/MetaCorePlayer/main.cpp @@ -233,21 +214,26 @@ add_executable(MetaCorePlayer target_link_libraries(MetaCorePlayer PRIVATE MetaCoreFoundation + MetaCorePlatform + MetaCoreRender + MetaCoreScene + MetaCorePanda3D::SDK ) -metacore_copy_runtime_dlls(MetaCorePlayer) + +metacore_stage_panda3d_runtime(MetaCorePlayer) if(METACORE_BUILD_TESTS) enable_testing() add_executable(MetaCoreSmokeTests - Tests/MetaCoreSmokeTests.cpp + tests/MetaCoreSmokeTests.cpp ) target_link_libraries(MetaCoreSmokeTests PRIVATE MetaCoreEditor ) - metacore_copy_runtime_dlls(MetaCoreSmokeTests) + metacore_stage_panda3d_runtime(MetaCoreSmokeTests) add_test(NAME MetaCoreSmokeTests COMMAND MetaCoreSmokeTests) endif() diff --git a/CMakePresets.json b/CMakePresets.json index 0c496b4..84b924c 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -11,7 +11,7 @@ "hidden": true, "generator": "Visual Studio 17 2022", "binaryDir": "${sourceDir}/build/${presetName}", - "toolchainFile": "D:/vcpkg/scripts/buildsystems/vcpkg.cmake", + "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "cacheVariables": { "CMAKE_CXX_STANDARD": "20", "METACORE_BUILD_TESTS": "ON" diff --git a/README.md b/README.md index 46c9cb9..841034c 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,64 @@ # MetaCore -MetaCore 是一个以 Unity 工作流为参考的纯 C++ 编辑器原型工程。 +`MetaCore` 是一个基于 `Panda3D` 进行二次开发的 Unity-like 编辑器与引擎框架原型。 ## 当前目标 -- 使用 `GLFW + OpenGL + Dear ImGui Docking` 搭建最小可运行编辑器 -- 使用 `GameObject + Component` 模型组织场景 +- 以 `Panda3D` 作为底层引擎与运行时基础 +- 以 `Dear ImGui Docking` 搭建 Unity-like 编辑器工作流 +- 使用 `GameObject + Component` 模型组织编辑器语义层 - 先把 `Hierarchy / Scene / Inspector / Project / Console` 跑通 -- 先体现清晰的渲染架构,再以模块化方式持续增加功能 +- 在不破坏主架构的前提下,以模块化方式持续叠加功能 ## 技术栈 - `C++20` - `CMake` - `vcpkg` -- `GLFW` -- `glad` -- `OpenGL 3.3` +- `Panda3D 1.10.16` - `glm` - `Dear ImGui Docking` ## 目录结构 - `Source/MetaCoreFoundation`:基础服务 -- `Source/MetaCorePlatform`:窗口与输入 +- `Source/MetaCorePlatform`:Panda3D 宿主窗口与输入采集 - `Source/MetaCoreScene`:场景与对象模型 -- `Source/MetaCoreRender`:OpenGL 渲染架构 +- `Source/MetaCoreRender`:Panda3D 场景桥与显示区域驱动 - `Source/MetaCoreEditor`:编辑器模块与 Unity-like 界面 - `Apps/MetaCoreEditor`:编辑器程序入口 -- `Apps/MetaCorePlayer`:运行时占位入口 -- `Tests`:基础烟雾测试 +- `Apps/MetaCorePlayer`:运行时壳层入口 +- `tests`:基础烟雾测试 ## 构建 +前提: + +- 已安装 `vcpkg` +- 已设置环境变量 `VCPKG_ROOT` +- Windows 环境可联网时,`cmake configure` 会自动准备 `Panda3D 1.10.16` SDK +- 如果已经本地安装 Panda3D,可设置环境变量 `PANDA3D_ROOT` + ```powershell cmake --preset vs2022-debug cmake --build --preset build-debug ctest --preset test-debug ``` +如果希望生成更适合分发的可执行文件,可使用: + +```powershell +cmake --preset vs2022-release +cmake --build --preset build-release +``` + ## 当前完成内容 -- 单窗口 MetaCore 编辑器主循环 -- 场景视口离屏渲染 +- Panda3D 单窗口宿主 +- ImGui Docking 编辑器外壳 +- Panda3D 中央场景 DisplayRegion - 网格、坐标轴、立方体绘制 - `Hierarchy` 选择 - `Inspector` 中编辑 `Transform` -- 轨道/平移/缩放相机控制 +- `Alt+左键 / 中键 / 滚轮 / F` 相机交互 - 模块注册接口与内置编辑器模块 diff --git a/SandboxProject/Assets/Materials/default_pbr.material.json b/SandboxProject/Assets/Materials/default_pbr.material.json new file mode 100644 index 0000000..3d8836b --- /dev/null +++ b/SandboxProject/Assets/Materials/default_pbr.material.json @@ -0,0 +1,7 @@ +{ + "name": "DefaultPbr", + "shader_family": "simplepbr", + "base_color": [1.0, 1.0, 1.0, 1.0], + "roughness": 1.0, + "metallic": 0.0 +} diff --git a/SandboxProject/Assets/Materials/default_pbr.material.json.meta b/SandboxProject/Assets/Materials/default_pbr.material.json.meta new file mode 100644 index 0000000..806cdec --- /dev/null +++ b/SandboxProject/Assets/Materials/default_pbr.material.json.meta @@ -0,0 +1,5 @@ +{ + "id": "00005031af6c28bc73f3772350037bcf00000005", + "relative_path": "Assets/Materials/default_pbr.material.json", + "type": "material" +} \ No newline at end of file diff --git a/SandboxProject/Assets/UI/main_menu.rcss b/SandboxProject/Assets/UI/main_menu.rcss new file mode 100644 index 0000000..c46e6b4 --- /dev/null +++ b/SandboxProject/Assets/UI/main_menu.rcss @@ -0,0 +1,10 @@ +body { + font-family: sans-serif; + color: #f2f4f8; +} +.root-panel { + width: 420px; + margin: 40px auto; + padding: 24px; + background: rgba(16, 18, 24, 0.85); +} diff --git a/SandboxProject/Assets/UI/main_menu.rcss.meta b/SandboxProject/Assets/UI/main_menu.rcss.meta new file mode 100644 index 0000000..367f6b6 --- /dev/null +++ b/SandboxProject/Assets/UI/main_menu.rcss.meta @@ -0,0 +1,5 @@ +{ + "id": "00005031af6c1e30843b82e4691e8cba00000004", + "relative_path": "Assets/UI/main_menu.rcss", + "type": "ui_stylesheet" +} \ No newline at end of file diff --git a/SandboxProject/Assets/UI/main_menu.rml b/SandboxProject/Assets/UI/main_menu.rml new file mode 100644 index 0000000..8d9a751 --- /dev/null +++ b/SandboxProject/Assets/UI/main_menu.rml @@ -0,0 +1,11 @@ + + + + + +
+

MetaCore

+

Runtime UI scaffold

+
+ +
diff --git a/SandboxProject/Assets/UI/main_menu.rml.meta b/SandboxProject/Assets/UI/main_menu.rml.meta new file mode 100644 index 0000000..16c3705 --- /dev/null +++ b/SandboxProject/Assets/UI/main_menu.rml.meta @@ -0,0 +1,5 @@ +{ + "id": "00005031af6bf9783f1fb78dcaa5ed8900000003", + "relative_path": "Assets/UI/main_menu.rml", + "type": "ui_document" +} \ No newline at end of file diff --git a/SandboxProject/Library/AssetDB.json b/SandboxProject/Library/AssetDB.json new file mode 100644 index 0000000..5e304af --- /dev/null +++ b/SandboxProject/Library/AssetDB.json @@ -0,0 +1,19 @@ +{ + "records": [ + { + "id": "00005031af6bf9783f1fb78dcaa5ed8900000003", + "relative_path": "Assets/UI/main_menu.rml", + "type": "ui_document" + }, + { + "id": "00005031af6c1e30843b82e4691e8cba00000004", + "relative_path": "Assets/UI/main_menu.rcss", + "type": "ui_stylesheet" + }, + { + "id": "00005031af6c28bc73f3772350037bcf00000005", + "relative_path": "Assets/Materials/default_pbr.material.json", + "type": "material" + } + ] +} \ No newline at end of file diff --git a/SandboxProject/Library/Layout/MetaCoreOverlayShell_snapshot.txt b/SandboxProject/Library/Layout/MetaCoreOverlayShell_snapshot.txt new file mode 100644 index 0000000..74a0dd4 --- /dev/null +++ b/SandboxProject/Library/Layout/MetaCoreOverlayShell_snapshot.txt @@ -0,0 +1,68 @@ +Shell=MetaCoreOverlayShell, Menus=3, ToolbarGroups=3, Sections=7, Hierarchy=3, Assets=3, Inspector=Demo Cube, DrawCommands=11, DrawVertices=2698, DrawIndices=6627, DrawLists=9 +MetaCoreOverlayShell composition + [Menu] 文件 actions=2 + - 新建场景 [Ctrl+N] + - 保存场景 [Ctrl+S] + [Menu] 编辑 actions=4 + - 创建空对象 [Ctrl+Shift+N] + - 删除所选 [Delete] + - 重命名所选 [F2] + - 聚焦所选 [F] + [Menu] 视图 actions=5 + - 切换层级 + - 切换检查器 + - 切换项目 + - 切换控制台 + - 切换运行时预览 + [Toolbar] 场景 actions=3 + - 创建空对象 + - 删除所选 + - 重命名所选 + [Toolbar] 选择 actions=1 + - 聚焦所选 + [Toolbar] 视图 actions=5 + - 切换层级 + - 切换检查器 + - 切换项目 + - 切换控制台 + - 切换运行时预览 + [Section] panels=1 + - 主菜单 (main_menu) + [Section] panels=1 + - 工具栏 (toolbar) + [Section] panels=2 + - 层级 (hierarchy) + - 项目 (project) + [Section] panels=1 + - 视口 (viewport) + [Section] panels=1 + - 检查器 (inspector) + [Section] panels=1 + - 控制台 (console) + [Section] panels=1 + - 运行时预览 (runtime_preview) +[Inspector] Demo Cube + - 标识: 00005031af7e8fac310b0d408494fcfb00000008 + - 位置: 0.000000, 0.000000, 0.000000 + - 旋转: 0.000000, 0.000000, 0.000000 + - 缩放: 1.000000, 1.000000, 1.000000 + - 网格: builtin://box +[Console] + - [System] MetaEditor initialized +[Viewport] + - Selection: Demo Cube + - SelectionId: 00005031af7e8fac310b0d408494fcfb00000008 + - Operation: Translate + - Space: Local + - SnapEnabled: false + - SnapValues: 1, 1, 1 + - Camera: 0.5, -2.5, 2 + - Position: 0, 0, 0 + - Rotation: 0, 0, 0 + - Scale: 1, 1, 1 + - FocusTarget: 00005031af7e8fac310b0d408494fcfb00000008 +[DrawData] + - CommandCount: 11 + - VertexCount: 2698 + - IndexCount: 6627 + - DrawLists: 9 diff --git a/SandboxProject/Library/Layout/editor_layout.json b/SandboxProject/Library/Layout/editor_layout.json new file mode 100644 index 0000000..5f38caa --- /dev/null +++ b/SandboxProject/Library/Layout/editor_layout.json @@ -0,0 +1,9 @@ +{ + "console_visible": true, + "hierarchy_visible": true, + "inspector_visible": true, + "layout_name": "Default", + "project_visible": true, + "runtime_preview_visible": true, + "toolbar_visible": true +} \ No newline at end of file diff --git a/SandboxProject/MetaCore.project.json b/SandboxProject/MetaCore.project.json new file mode 100644 index 0000000..c11066f --- /dev/null +++ b/SandboxProject/MetaCore.project.json @@ -0,0 +1,8 @@ +{ + "name": "MetaCoreSample", + "scenes": [ + "Scenes/Main.mcscene.json" + ], + "startup_scene": "Scenes/Main.mcscene.json", + "version": "0.1.0" +} \ No newline at end of file diff --git a/SandboxProject/Scenes/Main.mcscene.json b/SandboxProject/Scenes/Main.mcscene.json new file mode 100644 index 0000000..892c0bb --- /dev/null +++ b/SandboxProject/Scenes/Main.mcscene.json @@ -0,0 +1,108 @@ +{ + "name": "Main", + "objects": [ + { + "camera": { + "far_clip": 1000, + "fov_degrees": 60, + "near_clip": 0.100000001490116, + "primary": true + }, + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005031af666d280adc4216764a07c100000001", + "name": "Main Camera", + "parent_id": "", + "transform": { + "position": [ + 0, + -10, + 3 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005031af669a14494b5bcf7b0288f500000002", + "light": { + "color": [ + 1, + 1, + 1 + ], + "intensity": 1, + "range": 10, + "spot_angle_degrees": 45, + "type": "directional" + }, + "name": "Directional Light", + "parent_id": "", + "transform": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005031af7e8fac310b0d408494fcfb00000008", + "mesh_renderer": { + "material_asset_id": "builtin://editor-default", + "mesh_asset_id": "builtin://box", + "visible": true + }, + "name": "Demo Cube", + "parent_id": "", + "transform": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + } + ] +} \ No newline at end of file diff --git a/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp b/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp index 6dfed1c..569c5c1 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp +++ b/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp @@ -2,6 +2,7 @@ #include "MetaCoreEditor/MetaCoreEditorContext.h" #include "MetaCoreEditorCameraController.h" +#include "MetaCorePlatform/MetaCoreInput.h" #include "MetaCorePlatform/MetaCoreWindow.h" #include "MetaCoreRender/MetaCoreEditorViewportRenderer.h" #include "MetaCoreRender/MetaCoreRenderTypes.h" @@ -9,7 +10,6 @@ #include -#include #include #include @@ -62,7 +62,7 @@ public: editorContext.SetDockLayoutBuilt(false); } if (ImGui::MenuItem("退出")) { - glfwSetWindowShouldClose(editorContext.GetWindow().GetNativeHandle(), GLFW_TRUE); + editorContext.GetWindow().RequestClose(); } ImGui::EndMenu(); } @@ -108,7 +108,7 @@ public: } if (ImGui::BeginMenu("帮助")) { - ImGui::MenuItem("MetaCore Unity-like Prototype", nullptr, false, false); + ImGui::MenuItem("MetaCore Panda3D Editor Prototype", nullptr, false, false); ImGui::EndMenu(); } } @@ -138,27 +138,6 @@ public: void DrawPanel(MetaCoreEditorContext& editorContext) override { MetaCoreSceneViewportState& viewportState = editorContext.GetSceneViewportState(); - viewportState.Hovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); - viewportState.Focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); - - if (viewportState.Focused && editorContext.GetInput().WasKeyPressed(GLFW_KEY_F)) { - if (MetaCoreGameObject* selectedObject = editorContext.GetSelectedGameObject(); selectedObject != nullptr) { - editorContext.GetCameraController().FocusGameObject(*selectedObject); - editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "Scene", "相机已聚焦到当前对象"); - } - } - - editorContext.GetCameraController().Update(viewportState, editorContext.GetInput()); - - ImGui::Text("对象数: %d", static_cast(editorContext.GetScene().GetGameObjects().size())); - ImGui::SameLine(); - if (const MetaCoreGameObject* selectedObject = editorContext.GetSelectedGameObject(); selectedObject != nullptr) { - ImGui::Text("当前对象: %s", selectedObject->Name.c_str()); - } else { - ImGui::TextUnformatted("当前对象: 无"); - } - ImGui::Separator(); - ImVec2 viewportSize = ImGui::GetContentRegionAvail(); if (viewportSize.x < 1.0F) { viewportSize.x = 1.0F; @@ -167,30 +146,52 @@ public: viewportSize.y = 1.0F; } + const ImVec2 viewportScreenPosition = ImGui::GetCursorScreenPos(); + ImGui::InvisibleButton("MetaCoreSceneViewport", viewportSize, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonMiddle); + + const ImVec2 mainViewportPosition = ImGui::GetMainViewport()->Pos; + viewportState.Left = viewportScreenPosition.x - mainViewportPosition.x; + viewportState.Top = viewportScreenPosition.y - mainViewportPosition.y; viewportState.Width = viewportSize.x; viewportState.Height = viewportSize.y; + viewportState.Hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); + viewportState.Focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); - editorContext.GetViewportRenderer().Resize(static_cast(viewportSize.x), static_cast(viewportSize.y)); + if (viewportState.Focused && !ImGui::GetIO().WantCaptureKeyboard && editorContext.GetInput().WasKeyPressed(MetaCoreInputKey::Focus)) { + if (MetaCoreGameObject* selectedObject = editorContext.GetSelectedGameObject(); selectedObject != nullptr) { + editorContext.GetCameraController().FocusGameObject(*selectedObject); + editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "Scene", "相机已聚焦到当前对象"); + } + } - MetaCoreSceneView sceneView; - sceneView.ViewMatrix = editorContext.GetCameraController().BuildViewMatrix(); - sceneView.ProjectionMatrix = editorContext.GetCameraController().BuildProjectionMatrix(viewportSize.x / viewportSize.y); - sceneView.CameraPosition = editorContext.GetCameraController().GetCameraPosition(); + editorContext.GetCameraController().Update(viewportState, editorContext.GetInput()); + + MetaCoreSceneView sceneView = editorContext.GetCameraController().BuildSceneView(); sceneView.SelectedObjectId = editorContext.GetSelectedObjectId(); + editorContext.GetViewportRenderer().SetViewportRect(MetaCoreViewportRect{ + viewportState.Left, + viewportState.Top, + viewportState.Width, + viewportState.Height + }); editorContext.GetViewportRenderer().RenderSceneToViewport(editorContext.GetScene(), sceneView); - ImGui::Image( - reinterpret_cast(static_cast(editorContext.GetViewportRenderer().GetColorTextureHandle())), - viewportSize, - ImVec2(0.0F, 1.0F), - ImVec2(1.0F, 0.0F) + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRect( + viewportScreenPosition, + ImVec2(viewportScreenPosition.x + viewportSize.x, viewportScreenPosition.y + viewportSize.y), + IM_COL32(96, 108, 122, 220), + 0.0F, + 0, + 1.0F ); - viewportState.Hovered = ImGui::IsItemHovered(); - viewportState.Focused = viewportState.Focused || ImGui::IsItemFocused(); - - ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 28.0F); - ImGui::TextDisabled("Alt+左键 环绕 | 中键 平移 | 滚轮 缩放 | F 聚焦"); + const char* helpText = "Alt+左键 环绕 | 中键 平移 | 滚轮 缩放 | F 聚焦"; + drawList->AddText( + ImVec2(viewportScreenPosition.x + 12.0F, viewportScreenPosition.y + 10.0F), + IM_COL32(220, 224, 230, 220), + helpText + ); } }; diff --git a/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp b/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp index d479492..86ac8e7 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp +++ b/Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp @@ -5,8 +5,13 @@ #include #include -#include #include +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include #include #include @@ -14,6 +19,8 @@ #include #include +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + namespace MetaCore { namespace { @@ -27,7 +34,7 @@ void MetaCoreApplyEditorStyle() { style.WindowBorderSize = 1.0F; style.FramePadding = ImVec2(8.0F, 4.0F); style.ItemSpacing = ImVec2(8.0F, 5.0F); - style.Colors[ImGuiCol_WindowBg] = ImVec4(0.11F, 0.12F, 0.14F, 1.0F); + style.Colors[ImGuiCol_WindowBg] = ImVec4(0.11F, 0.12F, 0.14F, 0.97F); style.Colors[ImGuiCol_TitleBg] = ImVec4(0.10F, 0.11F, 0.13F, 1.0F); style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.14F, 0.15F, 0.17F, 1.0F); style.Colors[ImGuiCol_Header] = ImVec4(0.17F, 0.20F, 0.24F, 1.0F); @@ -37,6 +44,7 @@ void MetaCoreApplyEditorStyle() { style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.27F, 0.33F, 0.39F, 1.0F); style.Colors[ImGuiCol_Tab] = ImVec4(0.12F, 0.14F, 0.16F, 1.0F); style.Colors[ImGuiCol_TabSelected] = ImVec4(0.20F, 0.26F, 0.34F, 1.0F); + style.Colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.0F, 0.0F, 0.0F, 0.0F); } void MetaCoreConfigureChineseFont() { @@ -87,7 +95,16 @@ bool MetaCoreEditorApp::Initialize() { return false; } - if (!RenderDevice_.Initialize(Window_.GetNativeHandle())) { + Window_.SetNativeWindowMessageHandler([](void* nativeWindowHandle, unsigned int message, std::uintptr_t wparam, std::intptr_t lparam) { + ImGui_ImplWin32_WndProcHandler( + static_cast(nativeWindowHandle), + message, + static_cast(wparam), + static_cast(lparam) + ); + }); + + if (!RenderDevice_.Initialize(Window_)) { return false; } @@ -95,7 +112,7 @@ bool MetaCoreEditorApp::Initialize() { return false; } - if (!ViewportRenderer_.Initialize()) { + if (!ViewportRenderer_.Initialize(RenderDevice_)) { return false; } @@ -123,7 +140,7 @@ bool MetaCoreEditorApp::Initialize() { } EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "System", "MetaCore 编辑器已初始化"); - EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Render", "OpenGL 场景视口已准备完成"); + EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Render", "Panda3D 场景视口已准备完成"); Initialized_ = true; return true; @@ -134,15 +151,15 @@ int MetaCoreEditorApp::Run() { Window_.BeginFrame(); ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); + ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); DrawEditorFrame(); ImGui::Render(); - const auto [framebufferWidth, framebufferHeight] = Window_.GetFramebufferSize(); - RenderDevice_.BeginFrame(framebufferWidth, framebufferHeight, glm::vec4(0.08F, 0.09F, 0.11F, 1.0F)); + RenderDevice_.RenderFrame(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + RenderDevice_.PresentFrame(); Window_.EndFrame(); } @@ -175,11 +192,11 @@ bool MetaCoreEditorApp::InitializeImGui() { MetaCoreConfigureChineseFont(); MetaCoreApplyEditorStyle(); - if (!ImGui_ImplGlfw_InitForOpenGL(Window_.GetNativeHandle(), true)) { + if (!ImGui_ImplWin32_InitForOpenGL(Window_.GetNativeWindowHandle())) { return false; } - if (!ImGui_ImplOpenGL3_Init("#version 330")) { + if (!ImGui_ImplOpenGL3_Init("#version 130")) { return false; } @@ -188,7 +205,7 @@ bool MetaCoreEditorApp::InitializeImGui() { void MetaCoreEditorApp::ShutdownImGui() { ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); + ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); } @@ -203,6 +220,7 @@ void MetaCoreEditorApp::DrawEditorFrame() { ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_MenuBar; @@ -225,15 +243,80 @@ void MetaCoreEditorApp::DrawEditorFrame() { EnsureDefaultDockLayout(dockSpaceId); ImGui::End(); + MetaCoreIEditorPanelProvider* scenePanelProvider = nullptr; for (const auto& panelProvider : ModuleRegistry_.GetPanelProviders()) { + if (panelProvider->GetPanelId() == "Scene") { + scenePanelProvider = panelProvider.get(); + continue; + } + bool& panelOpen = ModuleRegistry_.AccessPanelOpenState(panelProvider->GetPanelId()); if (!panelOpen) { continue; } - ImGui::Begin(panelProvider->GetPanelTitle().c_str(), &panelOpen); + bool pushedTransparentColors = false; + if (panelProvider->WantsTransparentBackground()) { + ImGui::SetNextWindowBgAlpha(0.0F); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F)); + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F)); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F)); + pushedTransparentColors = true; + } + + bool pushedPadding = false; + if (panelProvider->WantsZeroPadding()) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0F, 0.0F)); + pushedPadding = true; + } + + const ImGuiWindowFlags panelWindowFlags = static_cast(panelProvider->GetWindowFlags()); + ImGui::Begin(panelProvider->GetPanelTitle().c_str(), &panelOpen, panelWindowFlags); panelProvider->DrawPanel(*EditorContext_); ImGui::End(); + + if (pushedPadding) { + ImGui::PopStyleVar(); + } + + if (pushedTransparentColors) { + ImGui::PopStyleColor(3); + } + } + + if (scenePanelProvider != nullptr && ModuleRegistry_.IsPanelOpen("Scene")) { + ImGuiDockNode* centralNode = ImGui::DockBuilderGetCentralNode(dockSpaceId); + if (centralNode != nullptr) { + const ImVec2 overlayPosition = centralNode->Pos; + const ImVec2 overlaySize = centralNode->Size; + + ImGui::SetNextWindowPos(overlayPosition); + ImGui::SetNextWindowSize(overlaySize); + 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)); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F)); + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F)); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.0F, 0.0F, 0.0F, 0.0F)); + + constexpr ImGuiWindowFlags sceneOverlayFlags = + ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoDocking | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoNavFocus | + ImGuiWindowFlags_NoBackground; + + bool sceneOpen = true; + ImGui::Begin("MetaCoreSceneOverlay", &sceneOpen, sceneOverlayFlags); + scenePanelProvider->DrawPanel(*EditorContext_); + ImGui::End(); + + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(3); + } } } @@ -252,7 +335,6 @@ void MetaCoreEditorApp::EnsureDefaultDockLayout(unsigned int dockSpaceId) { const ImGuiID bottomNodeId = ImGui::DockBuilderSplitNode(mainNodeId, ImGuiDir_Down, 0.28F, nullptr, &mainNodeId); ImGui::DockBuilderDockWindow("层级", leftNodeId); - ImGui::DockBuilderDockWindow("场景", mainNodeId); ImGui::DockBuilderDockWindow("检查器", rightNodeId); ImGui::DockBuilderDockWindow("项目", bottomNodeId); ImGui::DockBuilderDockWindow("控制台", bottomNodeId); diff --git a/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.cpp b/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.cpp index a81a646..d764125 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.cpp +++ b/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.cpp @@ -5,9 +5,8 @@ #include -#include -#include -#include +#include +#include #include #include @@ -20,13 +19,16 @@ void MetaCoreEditorCameraController::Update(const MetaCoreSceneViewportState& vi } ImGuiIO& io = ImGui::GetIO(); + if (io.WantCaptureMouse) { + return; + } if (viewportState.Hovered && std::abs(io.MouseWheel) > 0.001F) { Distance_ *= (io.MouseWheel > 0.0F) ? 0.88F : 1.12F; Distance_ = std::clamp(Distance_, 1.5F, 40.0F); } - const bool altDown = input.IsKeyDown(GLFW_KEY_LEFT_ALT) || input.IsKeyDown(GLFW_KEY_RIGHT_ALT); + const bool altDown = input.IsKeyDown(MetaCoreInputKey::LeftAlt) || input.IsKeyDown(MetaCoreInputKey::RightAlt); if (viewportState.Hovered && altDown && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { YawDegrees_ += io.MouseDelta.x * 0.35F; PitchDegrees_ -= io.MouseDelta.y * 0.35F; @@ -48,13 +50,13 @@ void MetaCoreEditorCameraController::FocusGameObject(const MetaCoreGameObject& g Distance_ = std::max(3.5F, scaleRadius * 4.0F + 2.5F); } -glm::mat4 MetaCoreEditorCameraController::BuildViewMatrix() const { - return glm::lookAt(GetCameraPosition(), Target_, glm::vec3(0.0F, 1.0F, 0.0F)); -} - -glm::mat4 MetaCoreEditorCameraController::BuildProjectionMatrix(float aspectRatio) const { - aspectRatio = (aspectRatio > 0.01F) ? aspectRatio : 1.0F; - return glm::perspective(glm::radians(FieldOfViewDegrees_), aspectRatio, 0.1F, 200.0F); +MetaCoreSceneView MetaCoreEditorCameraController::BuildSceneView() const { + MetaCoreSceneView sceneView; + sceneView.CameraPosition = GetCameraPosition(); + sceneView.CameraTarget = Target_; + sceneView.CameraUp = glm::vec3(0.0F, 1.0F, 0.0F); + sceneView.VerticalFieldOfViewDegrees = FieldOfViewDegrees_; + return sceneView; } glm::vec3 MetaCoreEditorCameraController::GetCameraPosition() const { diff --git a/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.h b/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.h index 37833a9..5f805f2 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.h +++ b/Source/MetaCoreEditor/Private/MetaCoreEditorCameraController.h @@ -1,8 +1,8 @@ #pragma once #include "MetaCoreEditor/MetaCoreEditorContext.h" +#include "MetaCoreRender/MetaCoreRenderTypes.h" -#include #include namespace MetaCore { @@ -10,13 +10,11 @@ namespace MetaCore { class MetaCoreInput; struct MetaCoreGameObject; -// 负责场景视口相机的轨道、平移、缩放与聚焦控制。 class MetaCoreEditorCameraController { public: void Update(const MetaCoreSceneViewportState& viewportState, const MetaCoreInput& input); void FocusGameObject(const MetaCoreGameObject& gameObject); - [[nodiscard]] glm::mat4 BuildViewMatrix() const; - [[nodiscard]] glm::mat4 BuildProjectionMatrix(float aspectRatio) const; + [[nodiscard]] MetaCoreSceneView BuildSceneView() const; [[nodiscard]] glm::vec3 GetCameraPosition() const; private: diff --git a/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h b/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h index cbb6398..8cb5bd1 100644 --- a/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h +++ b/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h @@ -17,15 +17,15 @@ struct MetaCoreGameObject; class MetaCoreEditorModuleRegistry; class MetaCoreEditorCameraController; -// 描述场景视口当前的尺寸与焦点状态。 struct MetaCoreSceneViewportState { + float Left = 0.0F; + float Top = 0.0F; float Width = 1.0F; float Height = 1.0F; bool Hovered = false; bool Focused = false; }; -// 在编辑器各模块之间共享运行时状态。 class MetaCoreEditorContext { public: MetaCoreEditorContext( diff --git a/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h b/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h index f0e3630..337aaf2 100644 --- a/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h +++ b/Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h @@ -10,7 +10,6 @@ namespace MetaCore { class MetaCoreEditorContext; struct MetaCoreGameObject; -// 定义可向编辑器注册菜单的扩展接口。 class MetaCoreIMenuProvider { public: virtual ~MetaCoreIMenuProvider() = default; @@ -18,17 +17,18 @@ public: virtual void DrawMenuBar(MetaCoreEditorContext& editorContext) = 0; }; -// 定义可向编辑器注册面板的扩展接口。 class MetaCoreIEditorPanelProvider { public: virtual ~MetaCoreIEditorPanelProvider() = default; [[nodiscard]] virtual std::string GetPanelId() const = 0; [[nodiscard]] virtual std::string GetPanelTitle() const = 0; [[nodiscard]] virtual bool IsOpenByDefault() const = 0; + [[nodiscard]] virtual int GetWindowFlags() const { return 0; } + [[nodiscard]] virtual bool WantsTransparentBackground() const { return false; } + [[nodiscard]] virtual bool WantsZeroPadding() const { return false; } virtual void DrawPanel(MetaCoreEditorContext& editorContext) = 0; }; -// 定义可向 Inspector 注册组件绘制器的扩展接口。 class MetaCoreIInspectorDrawer { public: virtual ~MetaCoreIInspectorDrawer() = default; @@ -37,7 +37,6 @@ public: virtual void DrawInspector(MetaCoreEditorContext& editorContext, MetaCoreGameObject& gameObject) = 0; }; -// 管理编辑器中全部可扩展菜单、面板和 Inspector 绘制器。 class MetaCoreEditorModuleRegistry { public: void RegisterMenuProvider(std::unique_ptr provider); @@ -58,7 +57,6 @@ private: std::unordered_map PanelOpenStates_{}; }; -// 定义一个可注册到编辑器中的模块生命周期接口。 class MetaCoreIModule { public: virtual ~MetaCoreIModule() = default; diff --git a/Source/MetaCorePlatform/Private/MetaCoreInput.cpp b/Source/MetaCorePlatform/Private/MetaCoreInput.cpp index aafac35..1d2c104 100644 --- a/Source/MetaCorePlatform/Private/MetaCoreInput.cpp +++ b/Source/MetaCorePlatform/Private/MetaCoreInput.cpp @@ -1,53 +1,49 @@ #include "MetaCorePlatform/MetaCoreInput.h" -#include - namespace MetaCore { -void MetaCoreInput::BeginFrame(GLFWwindow* nativeWindow) { +void MetaCoreInput::BeginFrame() { PreviousKeyStates_ = CurrentKeyStates_; PreviousMouseStates_ = CurrentMouseStates_; - - for (int key = 0; key < static_cast(CurrentKeyStates_.size()); ++key) { - CurrentKeyStates_[static_cast(key)] = glfwGetKey(nativeWindow, key) == GLFW_PRESS; - } - - for (int button = 0; button < static_cast(CurrentMouseStates_.size()); ++button) { - CurrentMouseStates_[static_cast(button)] = glfwGetMouseButton(nativeWindow, button) == GLFW_PRESS; - } - - double cursorX = 0.0; - double cursorY = 0.0; - glfwGetCursorPos(nativeWindow, &cursorX, &cursorY); - - const glm::vec2 previousPosition = CursorPosition_; - CursorPosition_ = glm::vec2(static_cast(cursorX), static_cast(cursorY)); - CursorDelta_ = CursorPosition_ - previousPosition; + PreviousCursorPosition_ = CursorPosition_; + CursorDelta_ = glm::vec2(0.0F, 0.0F); + MouseWheelDelta_ = 0.0F; } -bool MetaCoreInput::IsKeyDown(int key) const { - if (key < 0 || key >= static_cast(CurrentKeyStates_.size())) { - return false; - } +void MetaCoreInput::SetKeyState(MetaCoreInputKey key, bool isDown) { + CurrentKeyStates_[static_cast(key)] = isDown; +} + +void MetaCoreInput::SetMouseButtonState(MetaCoreMouseButton button, bool isDown) { + CurrentMouseStates_[static_cast(button)] = isDown; +} + +void MetaCoreInput::SetCursorPosition(const glm::vec2& cursorPosition) { + CursorPosition_ = cursorPosition; + CursorDelta_ = CursorPosition_ - PreviousCursorPosition_; +} + +void MetaCoreInput::AddMouseWheelDelta(float delta) { + MouseWheelDelta_ += delta; +} + +bool MetaCoreInput::IsKeyDown(MetaCoreInputKey key) const { return CurrentKeyStates_[static_cast(key)]; } -bool MetaCoreInput::WasKeyPressed(int key) const { - if (key < 0 || key >= static_cast(CurrentKeyStates_.size())) { - return false; - } - - const std::size_t index = static_cast(key); - return CurrentKeyStates_[index] && !PreviousKeyStates_[index]; +bool MetaCoreInput::WasKeyPressed(MetaCoreInputKey key) const { + const std::size_t keyIndex = static_cast(key); + return CurrentKeyStates_[keyIndex] && !PreviousKeyStates_[keyIndex]; } -bool MetaCoreInput::IsMouseButtonDown(int button) const { - if (button < 0 || button >= static_cast(CurrentMouseStates_.size())) { - return false; - } +bool MetaCoreInput::IsMouseButtonDown(MetaCoreMouseButton button) const { return CurrentMouseStates_[static_cast(button)]; } +float MetaCoreInput::GetMouseWheelDelta() const { + return MouseWheelDelta_; +} + const glm::vec2& MetaCoreInput::GetCursorPosition() const { return CursorPosition_; } diff --git a/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp b/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp index 097a957..4dc5fe4 100644 --- a/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp +++ b/Source/MetaCorePlatform/Private/MetaCoreWindow.cpp @@ -1,99 +1,259 @@ #include "MetaCorePlatform/MetaCoreWindow.h" -#include +#include "graphicsWindow.h" +#include "graphicsWindowProc.h" +#include "load_prc_file.h" +#include "nativeWindowHandle.h" +#include "pandaFramework.h" +#include "windowFramework.h" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include namespace MetaCore { +namespace { + +void MetaCoreConfigurePanda3D(const std::string& title) { + static bool configured = false; + if (configured) { + return; + } + + load_prc_file_data("", "load-display pandagl\n"); + load_prc_file_data("", "aux-display p3windisplay\n"); + load_prc_file_data("", "window-type onscreen\n"); + load_prc_file_data("", "model-path ./models\n"); + load_prc_file_data("", "sync-video false\n"); + 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"); + configured = true; +} + +HWND MetaCoreResolveNativeWindowHandle(GraphicsWindow* graphicsWindow) { + if (graphicsWindow == nullptr) { + return nullptr; + } + + WindowHandle* windowHandle = graphicsWindow->get_window_handle(); + if (windowHandle == nullptr) { + return nullptr; + } + + return reinterpret_cast(windowHandle->get_int_handle()); +} + +bool MetaCoreIsVirtualKeyDown(int virtualKey) { + return (GetAsyncKeyState(virtualKey) & 0x8000) != 0; +} + +} // namespace + +class MetaCoreWindow::MetaCoreWindowImpl { +public: + PandaFramework Framework{}; + WindowFramework* WindowFrameworkHandle = nullptr; + GraphicsWindow* GraphicsWindowHandle = nullptr; + HWND NativeHandle = nullptr; + MetaCoreInput Input{}; + MetaCoreNativeWindowMessageHandler MessageHandler{}; + std::unique_ptr MessageProc{}; + std::chrono::steady_clock::time_point LastFrameTime = std::chrono::steady_clock::now(); + float DeltaSeconds = 1.0F / 60.0F; + bool Initialized = false; + bool CloseRequested = false; +}; + +class MetaCoreWindowMessageProc final : public GraphicsWindowProc { +public: + explicit MetaCoreWindowMessageProc(MetaCoreWindow::MetaCoreWindowImpl& owner) + : Owner_(owner) { + } + + LONG wnd_proc(GraphicsWindow*, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override; + +private: + MetaCoreWindow::MetaCoreWindowImpl& Owner_; +}; + +LONG MetaCoreWindowMessageProc::wnd_proc(GraphicsWindow*, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if (Owner_.MessageHandler) { + Owner_.MessageHandler(hwnd, msg, static_cast(wparam), static_cast(lparam)); + } + + if (msg == WM_MOUSEWHEEL) { + Owner_.Input.AddMouseWheelDelta(static_cast(GET_WHEEL_DELTA_WPARAM(wparam)) / static_cast(WHEEL_DELTA)); + } else if (msg == WM_CLOSE) { + Owner_.CloseRequested = true; + } + + return 0; +} + +MetaCoreWindow::MetaCoreWindow() + : Impl_(std::make_unique()) { +} + MetaCoreWindow::~MetaCoreWindow() { Shutdown(); } bool MetaCoreWindow::Initialize(int width, int height, const std::string& title) { - if (NativeHandle_ != nullptr) { + if (Impl_->Initialized) { return true; } - if (glfwInit() != GLFW_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) { + Shutdown(); return false; } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#if defined(__APPLE__) - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); -#endif - - NativeHandle_ = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); - if (NativeHandle_ == nullptr) { - glfwTerminate(); + Impl_->GraphicsWindowHandle = Impl_->WindowFrameworkHandle->get_graphics_window(); + Impl_->NativeHandle = MetaCoreResolveNativeWindowHandle(Impl_->GraphicsWindowHandle); + if (Impl_->GraphicsWindowHandle == nullptr || Impl_->NativeHandle == nullptr) { + Shutdown(); return false; } - glfwMakeContextCurrent(NativeHandle_); - glfwSwapInterval(1); - LastFrameTime_ = glfwGetTime(); + Impl_->MessageProc = std::make_unique(*Impl_); + if (Impl_->GraphicsWindowHandle->supports_window_procs()) { + Impl_->GraphicsWindowHandle->add_window_proc(Impl_->MessageProc.get()); + } + + Impl_->CloseRequested = false; + Impl_->LastFrameTime = std::chrono::steady_clock::now(); + Impl_->Initialized = true; return true; } void MetaCoreWindow::Shutdown() { - if (NativeHandle_ != nullptr) { - glfwDestroyWindow(NativeHandle_); - NativeHandle_ = nullptr; - glfwTerminate(); + if (!Impl_->Initialized) { + return; } + + if (Impl_->GraphicsWindowHandle != nullptr && Impl_->MessageProc != nullptr && Impl_->GraphicsWindowHandle->supports_window_procs()) { + Impl_->GraphicsWindowHandle->remove_window_proc(Impl_->MessageProc.get()); + } + + Impl_->MessageProc.reset(); + + if (Impl_->WindowFrameworkHandle != nullptr) { + Impl_->Framework.close_window(Impl_->WindowFrameworkHandle); + Impl_->WindowFrameworkHandle = nullptr; + } + + Impl_->GraphicsWindowHandle = nullptr; + Impl_->NativeHandle = nullptr; + Impl_->Framework.close_framework(); + Impl_->Initialized = false; } void MetaCoreWindow::BeginFrame() { - glfwPollEvents(); - - const double currentTime = glfwGetTime(); - DeltaSeconds_ = static_cast(currentTime - LastFrameTime_); - LastFrameTime_ = currentTime; - - if (DeltaSeconds_ <= 0.0F) { - DeltaSeconds_ = 1.0F / 60.0F; + if (!Impl_->Initialized) { + return; } - Input_.BeginFrame(NativeHandle_); + const auto now = std::chrono::steady_clock::now(); + Impl_->DeltaSeconds = std::chrono::duration(now - Impl_->LastFrameTime).count(); + if (Impl_->DeltaSeconds <= 0.0F) { + Impl_->DeltaSeconds = 1.0F / 60.0F; + } + Impl_->LastFrameTime = now; + + Impl_->Input.BeginFrame(); + + if (Impl_->GraphicsWindowHandle != nullptr) { + Impl_->GraphicsWindowHandle->process_events(); + } + + Impl_->Input.SetKeyState(MetaCoreInputKey::LeftAlt, MetaCoreIsVirtualKeyDown(VK_LMENU)); + Impl_->Input.SetKeyState(MetaCoreInputKey::RightAlt, MetaCoreIsVirtualKeyDown(VK_RMENU)); + Impl_->Input.SetKeyState(MetaCoreInputKey::Focus, MetaCoreIsVirtualKeyDown('F')); + Impl_->Input.SetMouseButtonState(MetaCoreMouseButton::Left, MetaCoreIsVirtualKeyDown(VK_LBUTTON)); + Impl_->Input.SetMouseButtonState(MetaCoreMouseButton::Right, MetaCoreIsVirtualKeyDown(VK_RBUTTON)); + Impl_->Input.SetMouseButtonState(MetaCoreMouseButton::Middle, MetaCoreIsVirtualKeyDown(VK_MBUTTON)); + + POINT cursorPosition{}; + if (GetCursorPos(&cursorPosition) != FALSE && ScreenToClient(Impl_->NativeHandle, &cursorPosition) != FALSE) { + Impl_->Input.SetCursorPosition(glm::vec2(static_cast(cursorPosition.x), static_cast(cursorPosition.y))); + } } -void MetaCoreWindow::EndFrame() const { - glfwSwapBuffers(NativeHandle_); +void MetaCoreWindow::EndFrame() { } bool MetaCoreWindow::ShouldClose() const { - return NativeHandle_ == nullptr || glfwWindowShouldClose(NativeHandle_) == GLFW_TRUE; + return !Impl_->Initialized || Impl_->CloseRequested; } -GLFWwindow* MetaCoreWindow::GetNativeHandle() const { - return NativeHandle_; +void MetaCoreWindow::RequestClose() { + Impl_->CloseRequested = true; + if (Impl_->GraphicsWindowHandle != nullptr) { + Impl_->GraphicsWindowHandle->request_close(); + } +} + +void* MetaCoreWindow::GetNativeWindowHandle() const { + return Impl_->NativeHandle; +} + +void* MetaCoreWindow::GetNativeFrameworkHandle() const { + return &Impl_->Framework; +} + +void* MetaCoreWindow::GetNativeWindowFrameworkHandle() const { + return Impl_->WindowFrameworkHandle; +} + +void* MetaCoreWindow::GetNativeGraphicsWindowHandle() const { + return Impl_->GraphicsWindowHandle; } MetaCoreInput& MetaCoreWindow::GetInput() { - return Input_; + return Impl_->Input; } const MetaCoreInput& MetaCoreWindow::GetInput() const { - return Input_; + return Impl_->Input; } float MetaCoreWindow::GetDeltaSeconds() const { - return DeltaSeconds_; + return Impl_->DeltaSeconds; } std::pair MetaCoreWindow::GetWindowSize() const { - int width = 0; - int height = 0; - glfwGetWindowSize(NativeHandle_, &width, &height); - return {width, height}; + if (Impl_->GraphicsWindowHandle == nullptr) { + return {0, 0}; + } + + const WindowProperties windowProperties = Impl_->GraphicsWindowHandle->get_properties(); + return {windowProperties.get_x_size(), windowProperties.get_y_size()}; } std::pair MetaCoreWindow::GetFramebufferSize() const { - int width = 0; - int height = 0; - glfwGetFramebufferSize(NativeHandle_, &width, &height); - return {width, height}; + return GetWindowSize(); +} + +void MetaCoreWindow::SetNativeWindowMessageHandler(MetaCoreNativeWindowMessageHandler handler) { + Impl_->MessageHandler = std::move(handler); } } // namespace MetaCore diff --git a/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreInput.h b/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreInput.h index 3b05c2d..76b4e62 100644 --- a/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreInput.h +++ b/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreInput.h @@ -4,38 +4,72 @@ #include -struct GLFWwindow; - namespace MetaCore { -// 统一封装窗口轮询后的键鼠状态,避免上层直接依赖 GLFW 轮询细节。 +// 定义编辑器当前阶段需要识别的按键。 +enum class MetaCoreInputKey : unsigned int { + LeftAlt = 0, + RightAlt, + Focus, + Count +}; + +// 定义编辑器当前阶段需要识别的鼠标按键。 +enum class MetaCoreMouseButton : unsigned int { + Left = 0, + Right, + Middle, + Count +}; + +// 统一封装窗口层采集后的输入状态,避免上层直接依赖 Win32 或 Panda3D 细节。 class MetaCoreInput { public: - // 由窗口层在每帧轮询事件后刷新一次输入状态。 - void BeginFrame(GLFWwindow* nativeWindow); + // 在每帧开始时重置瞬时状态并保存上一帧快照。 + void BeginFrame(); + + // 由窗口层写入按键状态。 + void SetKeyState(MetaCoreInputKey key, bool isDown); + + // 由窗口层写入鼠标按键状态。 + void SetMouseButtonState(MetaCoreMouseButton button, bool isDown); + + // 由窗口层写入当前鼠标位置。 + void SetCursorPosition(const glm::vec2& cursorPosition); + + // 由窗口消息累加滚轮值,正值表示向前滚动。 + void AddMouseWheelDelta(float delta); // 判断按键当前是否处于按下状态。 - [[nodiscard]] bool IsKeyDown(int key) const; + [[nodiscard]] bool IsKeyDown(MetaCoreInputKey key) const; // 判断按键是否在本帧刚刚按下。 - [[nodiscard]] bool WasKeyPressed(int key) const; + [[nodiscard]] bool WasKeyPressed(MetaCoreInputKey key) const; // 判断鼠标按键当前是否按下。 - [[nodiscard]] bool IsMouseButtonDown(int button) const; + [[nodiscard]] bool IsMouseButtonDown(MetaCoreMouseButton button) const; + + // 返回当前帧累计的滚轮值。 + [[nodiscard]] float GetMouseWheelDelta() const; // 返回当前鼠标位置。 [[nodiscard]] const glm::vec2& GetCursorPosition() const; - // 返回本帧鼠标相对上一帧的位移。 + // 返回相对上一帧的鼠标位移。 [[nodiscard]] const glm::vec2& GetCursorDelta() const; private: - std::array CurrentKeyStates_{}; - std::array PreviousKeyStates_{}; - std::array CurrentMouseStates_{}; - std::array PreviousMouseStates_{}; + static constexpr std::size_t KeyCount_ = static_cast(MetaCoreInputKey::Count); + static constexpr std::size_t MouseButtonCount_ = static_cast(MetaCoreMouseButton::Count); + + std::array CurrentKeyStates_{}; + std::array PreviousKeyStates_{}; + std::array CurrentMouseStates_{}; + std::array PreviousMouseStates_{}; glm::vec2 CursorPosition_{0.0F, 0.0F}; + glm::vec2 PreviousCursorPosition_{0.0F, 0.0F}; glm::vec2 CursorDelta_{0.0F, 0.0F}; + float MouseWheelDelta_ = 0.0F; }; } // namespace MetaCore diff --git a/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreWindow.h b/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreWindow.h index 9656d5a..90e361b 100644 --- a/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreWindow.h +++ b/Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreWindow.h @@ -2,55 +2,75 @@ #include "MetaCorePlatform/MetaCoreInput.h" +#include +#include +#include #include #include -struct GLFWwindow; - namespace MetaCore { -// 负责管理主窗口、时间步进和最基础的事件轮询。 +class MetaCoreRenderDevice; + +// 定义宿主窗口层向上暴露的原生消息回调,用于把 Win32 消息转交给 ImGui。 +using MetaCoreNativeWindowMessageHandler = std::function; + +// 封装 Panda3D 窗口、时间步进与基础输入采集。 class MetaCoreWindow { public: - MetaCoreWindow() = default; + class MetaCoreWindowImpl; + + MetaCoreWindow(); ~MetaCoreWindow(); - // 创建主窗口并初始化 OpenGL 上下文。 + // 创建 Panda3D 主窗口并准备输入采集。 bool Initialize(int width, int height, const std::string& title); - // 释放窗口及 GLFW 资源。 + // 释放窗口与 Panda3D 宿主资源。 void Shutdown(); - // 轮询事件并刷新输入状态。 + // 处理窗口事件、更新时间步进并刷新输入状态。 void BeginFrame(); - // 交换前后缓冲区。 - void EndFrame() const; + // 为未来扩展保留的帧结束入口。 + void EndFrame(); - // 返回窗口是否请求关闭。 + // 返回窗口是否请求退出。 [[nodiscard]] bool ShouldClose() const; - // 返回原生 GLFW 窗口指针。 - [[nodiscard]] GLFWwindow* GetNativeHandle() const; + // 主动请求窗口退出。 + void RequestClose(); + + // 返回原生窗口句柄,供 ImGui Win32 backend 初始化使用。 + [[nodiscard]] void* GetNativeWindowHandle() const; + + // 返回 PandaFramework 原生对象指针,仅供底层桥接层使用。 + [[nodiscard]] void* GetNativeFrameworkHandle() const; + + // 返回 WindowFramework 原生对象指针,仅供底层桥接层使用。 + [[nodiscard]] void* GetNativeWindowFrameworkHandle() const; + + // 返回 GraphicsWindow 原生对象指针,仅供底层桥接层使用。 + [[nodiscard]] void* GetNativeGraphicsWindowHandle() const; // 返回当前输入对象。 [[nodiscard]] MetaCoreInput& GetInput(); [[nodiscard]] const MetaCoreInput& GetInput() const; - // 返回当前帧的时间间隔,单位为秒。 + // 返回当前帧耗时,单位为秒。 [[nodiscard]] float GetDeltaSeconds() const; - // 返回窗口尺寸。 + // 返回当前窗口尺寸。 [[nodiscard]] std::pair GetWindowSize() const; - // 返回帧缓冲尺寸。 + // 返回当前帧缓冲尺寸。 [[nodiscard]] std::pair GetFramebufferSize() const; + // 注册原生消息回调。 + void SetNativeWindowMessageHandler(MetaCoreNativeWindowMessageHandler handler); + private: - GLFWwindow* NativeHandle_ = nullptr; - MetaCoreInput Input_{}; - float DeltaSeconds_ = 1.0F / 60.0F; - double LastFrameTime_ = 0.0; + std::unique_ptr Impl_{}; }; } // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCoreDebugGeometry.cpp b/Source/MetaCoreRender/Private/MetaCoreDebugGeometry.cpp deleted file mode 100644 index d1b864a..0000000 --- a/Source/MetaCoreRender/Private/MetaCoreDebugGeometry.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "MetaCoreRender/MetaCoreDebugGeometry.h" - -#include - -#include - -namespace MetaCore { - -namespace { - -MetaCoreVertex MetaCoreMakeVertex(const glm::vec3& position, const glm::vec3& normal, const glm::vec4& color) { - return MetaCoreVertex{position, normal, color}; -} - -} // namespace - -bool MetaCoreDebugGeometry::Initialize() { - std::vector gridVertices; - std::vector gridIndices; - std::uint32_t gridIndex = 0; - - constexpr int gridHalfExtent = 10; - for (int step = -gridHalfExtent; step <= gridHalfExtent; ++step) { - const bool isCenterLine = step == 0; - const glm::vec4 lineColor = isCenterLine - ? glm::vec4(0.34F, 0.38F, 0.42F, 1.0F) - : glm::vec4(0.22F, 0.24F, 0.28F, 1.0F); - - gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(static_cast(step), 0.0F, -static_cast(gridHalfExtent)), glm::vec3(0.0F), lineColor)); - gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(static_cast(step), 0.0F, static_cast(gridHalfExtent)), glm::vec3(0.0F), lineColor)); - gridIndices.push_back(gridIndex++); - gridIndices.push_back(gridIndex++); - - gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(-static_cast(gridHalfExtent), 0.0F, static_cast(step)), glm::vec3(0.0F), lineColor)); - gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(static_cast(gridHalfExtent), 0.0F, static_cast(step)), glm::vec3(0.0F), lineColor)); - gridIndices.push_back(gridIndex++); - gridIndices.push_back(gridIndex++); - } - - std::vector axesVertices{ - MetaCoreMakeVertex(glm::vec3(0.0F), glm::vec3(0.0F), glm::vec4(0.95F, 0.28F, 0.24F, 1.0F)), - MetaCoreMakeVertex(glm::vec3(1.5F, 0.0F, 0.0F), glm::vec3(0.0F), glm::vec4(0.95F, 0.28F, 0.24F, 1.0F)), - MetaCoreMakeVertex(glm::vec3(0.0F), glm::vec3(0.0F), glm::vec4(0.30F, 0.78F, 0.32F, 1.0F)), - MetaCoreMakeVertex(glm::vec3(0.0F, 1.5F, 0.0F), glm::vec3(0.0F), glm::vec4(0.30F, 0.78F, 0.32F, 1.0F)), - MetaCoreMakeVertex(glm::vec3(0.0F), glm::vec3(0.0F), glm::vec4(0.28F, 0.53F, 0.95F, 1.0F)), - MetaCoreMakeVertex(glm::vec3(0.0F, 0.0F, 1.5F), glm::vec3(0.0F), glm::vec4(0.28F, 0.53F, 0.95F, 1.0F)) - }; - std::vector axesIndices{0, 1, 2, 3, 4, 5}; - - const glm::vec4 cubeColor(1.0F, 1.0F, 1.0F, 1.0F); - std::vector cubeVertices{ - MetaCoreMakeVertex(glm::vec3(-0.5F, -0.5F, 0.5F), glm::vec3(0.0F, 0.0F, 1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, -0.5F, 0.5F), glm::vec3(0.0F, 0.0F, 1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, 0.5F, 0.5F), glm::vec3(0.0F, 0.0F, 1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, 0.5F, 0.5F), glm::vec3(0.0F, 0.0F, 1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, -0.5F, -0.5F), glm::vec3(0.0F, 0.0F, -1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, -0.5F, -0.5F), glm::vec3(0.0F, 0.0F, -1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, 0.5F, -0.5F), glm::vec3(0.0F, 0.0F, -1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, 0.5F, -0.5F), glm::vec3(0.0F, 0.0F, -1.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, 0.5F, 0.5F), glm::vec3(-1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, 0.5F, -0.5F), glm::vec3(-1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, -0.5F, -0.5F), glm::vec3(-1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, -0.5F, 0.5F), glm::vec3(-1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, 0.5F, 0.5F), glm::vec3(1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, 0.5F, -0.5F), glm::vec3(1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, -0.5F, -0.5F), glm::vec3(1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, -0.5F, 0.5F), glm::vec3(1.0F, 0.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, 0.5F, -0.5F), glm::vec3(0.0F, 1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, 0.5F, -0.5F), glm::vec3(0.0F, 1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, 0.5F, 0.5F), glm::vec3(0.0F, 1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, 0.5F, 0.5F), glm::vec3(0.0F, 1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, -0.5F, -0.5F), glm::vec3(0.0F, -1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, -0.5F, -0.5F), glm::vec3(0.0F, -1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3( 0.5F, -0.5F, 0.5F), glm::vec3(0.0F, -1.0F, 0.0F), cubeColor), - MetaCoreMakeVertex(glm::vec3(-0.5F, -0.5F, 0.5F), glm::vec3(0.0F, -1.0F, 0.0F), cubeColor) - }; - - std::vector cubeIndices{ - 0, 1, 2, 0, 2, 3, - 4, 6, 5, 4, 7, 6, - 8, 9, 10, 8, 10, 11, - 12, 14, 13, 12, 15, 14, - 16, 17, 18, 16, 18, 19, - 20, 22, 21, 20, 23, 22 - }; - - return GridMesh_.Build(gridVertices, gridIndices, MetaCorePrimitiveType::Lines) - && AxesMesh_.Build(axesVertices, axesIndices, MetaCorePrimitiveType::Lines) - && CubeMesh_.Build(cubeVertices, cubeIndices, MetaCorePrimitiveType::Triangles); -} - -void MetaCoreDebugGeometry::Shutdown() { - GridMesh_.Shutdown(); - AxesMesh_.Shutdown(); - CubeMesh_.Shutdown(); -} - -const MetaCoreMesh& MetaCoreDebugGeometry::GetGridMesh() const { - return GridMesh_; -} - -const MetaCoreMesh& MetaCoreDebugGeometry::GetAxesMesh() const { - return AxesMesh_; -} - -const MetaCoreMesh& MetaCoreDebugGeometry::GetCubeMesh() const { - return CubeMesh_; -} - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp b/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp index a3a33c2..ef98138 100644 --- a/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp +++ b/Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp @@ -1,116 +1,43 @@ #include "MetaCoreRender/MetaCoreEditorViewportRenderer.h" -#include "MetaCoreRender/MetaCoreSceneRenderer.h" +#include "MetaCoreRender/MetaCoreRenderDevice.h" #include "MetaCoreScene/MetaCoreScene.h" -#include - namespace MetaCore { -bool MetaCoreEditorViewportRenderer::Initialize() { +bool MetaCoreEditorViewportRenderer::Initialize(MetaCoreRenderDevice& renderDevice) { Shutdown(); - SceneRenderer_ = new MetaCoreSceneRenderer(); - if (!SceneRenderer_->Initialize()) { - Shutdown(); + if (!SceneBridge_.Initialize(renderDevice)) { return false; } - RebuildFramebuffer(); - return FramebufferHandle_ != 0; + RenderDevice_ = &renderDevice; + ViewportRect_ = MetaCoreViewportRect{}; + return true; } void MetaCoreEditorViewportRenderer::Shutdown() { - DestroyFramebuffer(); - - if (SceneRenderer_ != nullptr) { - SceneRenderer_->Shutdown(); - delete SceneRenderer_; - SceneRenderer_ = nullptr; - } + SceneBridge_.Shutdown(); + RenderDevice_ = nullptr; + ViewportRect_ = MetaCoreViewportRect{}; } -void MetaCoreEditorViewportRenderer::Resize(int width, int height) { - width = (width > 1) ? width : 1; - height = (height > 1) ? height : 1; - - if (width == Width_ && height == Height_) { - return; +void MetaCoreEditorViewportRenderer::SetViewportRect(const MetaCoreViewportRect& viewportRect) { + ViewportRect_ = viewportRect; + if (RenderDevice_ != nullptr) { + RenderDevice_->SetSceneViewportRect(ViewportRect_); } - - Width_ = width; - Height_ = height; - RebuildFramebuffer(); } void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView) { - if (FramebufferHandle_ == 0 || SceneRenderer_ == nullptr) { + if (RenderDevice_ == nullptr) { return; } - glBindFramebuffer(GL_FRAMEBUFFER, FramebufferHandle_); - glViewport(0, 0, Width_, Height_); - glEnable(GL_DEPTH_TEST); - glClearColor(0.09F, 0.10F, 0.12F, 1.0F); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - SceneRenderer_->RenderScene(scene, sceneView); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -unsigned int MetaCoreEditorViewportRenderer::GetColorTextureHandle() const { - return ColorTextureHandle_; -} - -int MetaCoreEditorViewportRenderer::GetWidth() const { - return Width_; -} - -int MetaCoreEditorViewportRenderer::GetHeight() const { - return Height_; -} - -void MetaCoreEditorViewportRenderer::RebuildFramebuffer() { - DestroyFramebuffer(); - - glGenFramebuffers(1, &FramebufferHandle_); - glBindFramebuffer(GL_FRAMEBUFFER, FramebufferHandle_); - - glGenTextures(1, &ColorTextureHandle_); - glBindTexture(GL_TEXTURE_2D, ColorTextureHandle_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width_, Height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ColorTextureHandle_, 0); - - glGenRenderbuffers(1, &DepthStencilHandle_); - glBindRenderbuffer(GL_RENDERBUFFER, DepthStencilHandle_); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, Width_, Height_); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, DepthStencilHandle_); - - glBindTexture(GL_TEXTURE_2D, 0); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void MetaCoreEditorViewportRenderer::DestroyFramebuffer() { - if (DepthStencilHandle_ != 0) { - glDeleteRenderbuffers(1, &DepthStencilHandle_); - DepthStencilHandle_ = 0; - } - - if (ColorTextureHandle_ != 0) { - glDeleteTextures(1, &ColorTextureHandle_); - ColorTextureHandle_ = 0; - } - - if (FramebufferHandle_ != 0) { - glDeleteFramebuffers(1, &FramebufferHandle_); - FramebufferHandle_ = 0; - } + RenderDevice_->SetSceneViewportRect(ViewportRect_); + SceneBridge_.ApplySceneView(sceneView); + SceneBridge_.SyncScene(scene); } } // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCoreMesh.cpp b/Source/MetaCoreRender/Private/MetaCoreMesh.cpp deleted file mode 100644 index efa26c4..0000000 --- a/Source/MetaCoreRender/Private/MetaCoreMesh.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "MetaCoreRender/MetaCoreMesh.h" - -#include - -namespace MetaCore { - -MetaCoreMesh::~MetaCoreMesh() { - Shutdown(); -} - -bool MetaCoreMesh::Build(const std::vector& vertices, const std::vector& indices, MetaCorePrimitiveType primitiveType) { - Shutdown(); - - PrimitiveType_ = primitiveType; - IndexCount_ = static_cast(indices.size()); - - glGenVertexArrays(1, &VertexArrayHandle_); - glGenBuffers(1, &VertexBufferHandle_); - glGenBuffers(1, &IndexBufferHandle_); - - glBindVertexArray(VertexArrayHandle_); - - glBindBuffer(GL_ARRAY_BUFFER, VertexBufferHandle_); - glBufferData( - GL_ARRAY_BUFFER, - static_cast(vertices.size() * sizeof(MetaCoreVertex)), - vertices.data(), - GL_STATIC_DRAW - ); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferHandle_); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - static_cast(indices.size() * sizeof(std::uint32_t)), - indices.data(), - GL_STATIC_DRAW - ); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MetaCoreVertex), reinterpret_cast(offsetof(MetaCoreVertex, Position))); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MetaCoreVertex), reinterpret_cast(offsetof(MetaCoreVertex, Normal))); - - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MetaCoreVertex), reinterpret_cast(offsetof(MetaCoreVertex, Color))); - - glBindVertexArray(0); - return true; -} - -void MetaCoreMesh::Shutdown() { - if (IndexBufferHandle_ != 0) { - glDeleteBuffers(1, &IndexBufferHandle_); - IndexBufferHandle_ = 0; - } - - if (VertexBufferHandle_ != 0) { - glDeleteBuffers(1, &VertexBufferHandle_); - VertexBufferHandle_ = 0; - } - - if (VertexArrayHandle_ != 0) { - glDeleteVertexArrays(1, &VertexArrayHandle_); - VertexArrayHandle_ = 0; - } - - IndexCount_ = 0; -} - -void MetaCoreMesh::Draw() const { - glBindVertexArray(VertexArrayHandle_); - glDrawElements( - PrimitiveType_ == MetaCorePrimitiveType::Triangles ? GL_TRIANGLES : GL_LINES, - static_cast(IndexCount_), - GL_UNSIGNED_INT, - nullptr - ); - glBindVertexArray(0); -} - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp b/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp new file mode 100644 index 0000000..47763a4 --- /dev/null +++ b/Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp @@ -0,0 +1,317 @@ +#include "MetaCoreRender/MetaCorePandaSceneBridge.h" + +#include "MetaCoreRender/MetaCoreRenderDevice.h" +#include "MetaCoreRender/MetaCoreRenderTypes.h" +#include "MetaCoreScene/MetaCoreComponents.h" +#include "MetaCoreScene/MetaCoreScene.h" + +#include "ambientLight.h" +#include "camera.h" +#include "directionalLight.h" +#include "lineSegs.h" +#include "loader.h" +#include "nodePath.h" +#include "perspectiveLens.h" +#include "pandaNode.h" +#include "windowFramework.h" + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +#include +#include +#include + +namespace MetaCore { + +namespace { + +glm::mat4 MetaCoreBuildBasisSwapMatrix() { + glm::mat4 basis(1.0F); + basis[0] = glm::vec4(1.0F, 0.0F, 0.0F, 0.0F); + basis[1] = glm::vec4(0.0F, 0.0F, 1.0F, 0.0F); + basis[2] = glm::vec4(0.0F, 1.0F, 0.0F, 0.0F); + basis[3] = glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + return basis; +} + +LMatrix4f MetaCoreConvertTransformToPanda(const MetaCoreTransformComponent& transform) { + const glm::mat4 translation = glm::translate(glm::mat4(1.0F), transform.Position); + const glm::mat4 rotation = glm::yawPitchRoll( + glm::radians(transform.RotationEulerDegrees.y), + glm::radians(transform.RotationEulerDegrees.x), + glm::radians(transform.RotationEulerDegrees.z) + ); + const glm::mat4 scale = glm::scale(glm::mat4(1.0F), transform.Scale); + + const glm::mat4 metaCoreMatrix = translation * rotation * scale; + const glm::mat4 basis = MetaCoreBuildBasisSwapMatrix(); + const glm::mat4 pandaMatrix = basis * metaCoreMatrix * basis; + + LMatrix4f result; + for (int row = 0; row < 4; ++row) { + for (int column = 0; column < 4; ++column) { + result.set_cell(row, column, pandaMatrix[column][row]); + } + } + return result; +} + +LPoint3f MetaCoreToPandaPoint(const glm::vec3& value) { + return LPoint3f(value.x, value.z, value.y); +} + +LVector3f MetaCoreToPandaVector(const glm::vec3& value) { + return LVector3f(value.x, value.z, value.y); +} + +NodePath MetaCoreCreateGridNode(const NodePath& parentNode) { + LineSegs gridBuilder("MetaCoreGrid"); + gridBuilder.set_thickness(1.0F); + + 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)))); + } + + return parentNode.attach_new_node(gridBuilder.create()); +} + +NodePath MetaCoreCreateAxisNode(const NodePath& parentNode) { + LineSegs axisBuilder("MetaCoreAxis"); + axisBuilder.set_thickness(3.0F); + + 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))); + + 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))); + + 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))); + + return parentNode.attach_new_node(axisBuilder.create()); +} + +} // namespace + +class MetaCorePandaSceneBridge::MetaCorePandaSceneBridgeImpl { +public: + struct MetaCorePandaObjectState { + NodePath RootNode{}; + NodePath MeshNode{}; + NodePath LightNode{}; + }; + + MetaCoreRenderDevice* RenderDevice = nullptr; + NodePath GridNode{}; + NodePath AxisNode{}; + NodePath AmbientLightNode{}; + MetaCoreId SelectedObjectId = 0; + std::unordered_map ObjectStates{}; +}; + +MetaCorePandaSceneBridge::MetaCorePandaSceneBridge() + : Impl_(std::make_unique()) { +} + +MetaCorePandaSceneBridge::~MetaCorePandaSceneBridge() { + Shutdown(); +} + +bool MetaCorePandaSceneBridge::Initialize(MetaCoreRenderDevice& renderDevice) { + Shutdown(); + + auto* windowFrameworkHandle = static_cast(renderDevice.GetNativeWindowFrameworkHandle()); + auto* sceneRootHandle = static_cast(renderDevice.GetNativeSceneRootHandle()); + if (windowFrameworkHandle == nullptr || sceneRootHandle == nullptr || sceneRootHandle->is_empty()) { + return false; + } + + Impl_->RenderDevice = &renderDevice; + Impl_->GridNode = MetaCoreCreateGridNode(*sceneRootHandle); + Impl_->AxisNode = MetaCoreCreateAxisNode(*sceneRootHandle); + Impl_->GridNode.set_light_off(1); + Impl_->AxisNode.set_light_off(1); + + PT(AmbientLight) ambientLight = new AmbientLight("MetaCoreAmbientLight"); + ambientLight->set_color(LColor(0.85F, 0.85F, 0.85F, 1.0F)); + Impl_->AmbientLightNode = sceneRootHandle->attach_new_node(ambientLight); + sceneRootHandle->set_light(Impl_->AmbientLightNode); + + return true; +} + +void MetaCorePandaSceneBridge::Shutdown() { + if (Impl_ == nullptr) { + return; + } + + for (auto& [objectId, objectState] : Impl_->ObjectStates) { + (void)objectId; + if (!objectState.RootNode.is_empty()) { + objectState.RootNode.remove_node(); + } + } + Impl_->ObjectStates.clear(); + + if (!Impl_->AmbientLightNode.is_empty()) { + Impl_->AmbientLightNode.remove_node(); + Impl_->AmbientLightNode = NodePath(); + } + + if (!Impl_->AxisNode.is_empty()) { + Impl_->AxisNode.remove_node(); + Impl_->AxisNode = NodePath(); + } + + if (!Impl_->GridNode.is_empty()) { + Impl_->GridNode.remove_node(); + Impl_->GridNode = NodePath(); + } + + Impl_->RenderDevice = nullptr; + Impl_->SelectedObjectId = 0; +} + +void MetaCorePandaSceneBridge::SyncScene(const MetaCoreScene& scene) { + if (Impl_->RenderDevice == nullptr) { + return; + } + + auto* windowFrameworkHandle = static_cast(Impl_->RenderDevice->GetNativeWindowFrameworkHandle()); + auto* sceneRootHandle = static_cast(Impl_->RenderDevice->GetNativeSceneRootHandle()); + if (windowFrameworkHandle == nullptr || sceneRootHandle == nullptr || sceneRootHandle->is_empty()) { + return; + } + + std::unordered_set aliveObjectIds; + + for (const MetaCoreGameObject& gameObject : scene.GetGameObjects()) { + aliveObjectIds.insert(gameObject.Id); + auto [iterator, inserted] = Impl_->ObjectStates.try_emplace(gameObject.Id); + MetaCorePandaSceneBridgeImpl::MetaCorePandaObjectState& objectState = iterator->second; + + if (inserted || objectState.RootNode.is_empty()) { + PT(PandaNode) rootNode = new PandaNode(gameObject.Name); + objectState.RootNode = sceneRootHandle->attach_new_node(rootNode); + } + + objectState.RootNode.set_name(gameObject.Name); + objectState.RootNode.set_mat(MetaCoreConvertTransformToPanda(gameObject.Transform)); + + if (gameObject.ParentId != 0) { + const auto parentIterator = Impl_->ObjectStates.find(gameObject.ParentId); + if (parentIterator != Impl_->ObjectStates.end() && !parentIterator->second.RootNode.is_empty()) { + objectState.RootNode.reparent_to(parentIterator->second.RootNode); + } else { + objectState.RootNode.reparent_to(*sceneRootHandle); + } + } else { + objectState.RootNode.reparent_to(*sceneRootHandle); + } + + if (gameObject.MeshRenderer.has_value()) { + if (objectState.MeshNode.is_empty()) { + objectState.MeshNode = windowFrameworkHandle->load_model(objectState.RootNode, Filename("models/box")); + } + + if (!objectState.MeshNode.is_empty()) { + objectState.MeshNode.set_texture_off(1); + objectState.MeshNode.set_material_off(1); + objectState.MeshNode.set_shader_off(1); + objectState.MeshNode.set_light_off(1); + objectState.MeshNode.set_two_sided(true); + objectState.MeshNode.set_color( + gameObject.MeshRenderer->BaseColor.r, + gameObject.MeshRenderer->BaseColor.g, + gameObject.MeshRenderer->BaseColor.b, + 1.0F + ); + + if (gameObject.MeshRenderer->Visible) { + objectState.MeshNode.show(); + } else { + objectState.MeshNode.hide(); + } + + if (gameObject.Id == Impl_->SelectedObjectId) { + objectState.MeshNode.set_color_scale(1.18F, 1.02F, 0.72F, 1.0F); + } else { + objectState.MeshNode.clear_color_scale(); + } + } + } else if (!objectState.MeshNode.is_empty()) { + objectState.MeshNode.remove_node(); + objectState.MeshNode = NodePath(); + } + + if (gameObject.Light.has_value()) { + if (objectState.LightNode.is_empty()) { + PT(DirectionalLight) directionalLight = new DirectionalLight(gameObject.Name); + objectState.LightNode = objectState.RootNode.attach_new_node(directionalLight); + sceneRootHandle->set_light(objectState.LightNode); + } + + auto* directionalLight = DCAST(DirectionalLight, objectState.LightNode.node()); + if (directionalLight != nullptr) { + directionalLight->set_color(LColor( + gameObject.Light->Color.r * gameObject.Light->Intensity, + gameObject.Light->Color.g * gameObject.Light->Intensity, + gameObject.Light->Color.b * gameObject.Light->Intensity, + 1.0F + )); + } + } else if (!objectState.LightNode.is_empty()) { + sceneRootHandle->clear_light(objectState.LightNode); + objectState.LightNode.remove_node(); + objectState.LightNode = NodePath(); + } + } + + for (auto iterator = Impl_->ObjectStates.begin(); iterator != Impl_->ObjectStates.end();) { + if (!aliveObjectIds.contains(iterator->first)) { + if (!iterator->second.RootNode.is_empty()) { + iterator->second.RootNode.remove_node(); + } + iterator = Impl_->ObjectStates.erase(iterator); + } else { + ++iterator; + } + } +} + +void MetaCorePandaSceneBridge::ApplySceneView(const MetaCoreSceneView& sceneView) { + if (Impl_->RenderDevice == nullptr) { + return; + } + + auto* editorCameraHandle = static_cast(Impl_->RenderDevice->GetNativeEditorCameraHandle()); + if (editorCameraHandle == nullptr || editorCameraHandle->is_empty()) { + return; + } + + Impl_->SelectedObjectId = sceneView.SelectedObjectId; + + editorCameraHandle->set_pos(MetaCoreToPandaPoint(sceneView.CameraPosition)); + editorCameraHandle->look_at(MetaCoreToPandaPoint(sceneView.CameraTarget), MetaCoreToPandaVector(sceneView.CameraUp)); + + auto* cameraNode = DCAST(Camera, editorCameraHandle->node()); + if (cameraNode != nullptr) { + auto* perspectiveLens = DCAST(PerspectiveLens, cameraNode->get_lens()); + if (perspectiveLens != nullptr) { + perspectiveLens->set_fov(sceneView.VerticalFieldOfViewDegrees); + } + } +} + +} // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp b/Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp index 84d6c86..ec4272b 100644 --- a/Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp +++ b/Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp @@ -1,45 +1,170 @@ #include "MetaCoreRender/MetaCoreRenderDevice.h" -#include -#include +#include "MetaCorePlatform/MetaCoreWindow.h" + +#include "camera.h" +#include "displayRegion.h" +#include "graphicsEngine.h" +#include "graphicsWindow.h" +#include "pandaFramework.h" +#include "pandaNode.h" +#include "perspectiveLens.h" +#include "windowFramework.h" + +#include +#include namespace MetaCore { -bool MetaCoreRenderDevice::Initialize(GLFWwindow* nativeWindow) { - if (Initialized_) { +class MetaCoreRenderDevice::MetaCoreRenderDeviceImpl { +public: + MetaCoreWindow* Window = nullptr; + PandaFramework* Framework = nullptr; + WindowFramework* WindowFrameworkHandle = nullptr; + GraphicsWindow* GraphicsWindowHandle = nullptr; + GraphicsEngine* GraphicsEngineHandle = nullptr; + DisplayRegion* SceneDisplayRegion = nullptr; + NodePath SceneRoot{}; + NodePath EditorCamera{}; + bool Initialized = false; +}; + +MetaCoreRenderDevice::MetaCoreRenderDevice() + : Impl_(std::make_unique()) { +} + +MetaCoreRenderDevice::~MetaCoreRenderDevice() { + Shutdown(); +} + +bool MetaCoreRenderDevice::Initialize(MetaCoreWindow& window) { + if (Impl_->Initialized) { return true; } - if (gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress)) == 0) { + auto* frameworkHandle = static_cast(window.GetNativeFrameworkHandle()); + auto* windowFrameworkHandle = static_cast(window.GetNativeWindowFrameworkHandle()); + auto* graphicsWindowHandle = static_cast(window.GetNativeGraphicsWindowHandle()); + if (frameworkHandle == nullptr || windowFrameworkHandle == nullptr || graphicsWindowHandle == nullptr) { return false; } - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - glDisable(GL_BLEND); - Initialized_ = nativeWindow != nullptr; - return Initialized_; + Impl_->Window = &window; + Impl_->Framework = frameworkHandle; + Impl_->WindowFrameworkHandle = windowFrameworkHandle; + Impl_->GraphicsWindowHandle = graphicsWindowHandle; + Impl_->GraphicsEngineHandle = frameworkHandle->get_graphics_engine(); + if (Impl_->GraphicsEngineHandle == nullptr) { + return false; + } + + Impl_->GraphicsEngineHandle->set_auto_flip(false); + Impl_->GraphicsEngineHandle->open_windows(); + + if (Impl_->WindowFrameworkHandle->get_display_region_2d() != nullptr) { + Impl_->WindowFrameworkHandle->get_display_region_2d()->set_active(false); + } + + Impl_->SceneDisplayRegion = Impl_->WindowFrameworkHandle->get_display_region_3d(); + if (Impl_->SceneDisplayRegion == nullptr) { + return false; + } + + Impl_->GraphicsWindowHandle->set_clear_color_active(true); + Impl_->GraphicsWindowHandle->set_clear_color(LColor(0.38F, 0.48F, 0.62F, 1.0F)); + + PT(PandaNode) sceneRootNode = new PandaNode("MetaCoreSceneRoot"); + Impl_->SceneRoot = Impl_->WindowFrameworkHandle->get_render().attach_new_node(sceneRootNode); + Impl_->SceneRoot.set_shader_auto(); + + Impl_->EditorCamera = Impl_->WindowFrameworkHandle->make_camera(); + Impl_->SceneDisplayRegion->set_camera(Impl_->EditorCamera); + Impl_->SceneDisplayRegion->set_sort(0); + Impl_->SceneDisplayRegion->set_scissor_enabled(true); + Impl_->SceneDisplayRegion->set_clear_color_active(false); + + if (auto* cameraNode = DCAST(Camera, Impl_->EditorCamera.node()); cameraNode != nullptr) { + PT(PerspectiveLens) lens = new PerspectiveLens(); + lens->set_fov(60.0F); + lens->set_near_far(0.05F, 500.0F); + cameraNode->set_lens(lens); + } + + Impl_->Initialized = true; + return true; } void MetaCoreRenderDevice::Shutdown() { - Initialized_ = false; + if (!Impl_->Initialized) { + return; + } + + if (!Impl_->EditorCamera.is_empty()) { + Impl_->EditorCamera.remove_node(); + Impl_->EditorCamera = NodePath(); + } + + if (!Impl_->SceneRoot.is_empty()) { + Impl_->SceneRoot.remove_node(); + Impl_->SceneRoot = NodePath(); + } + + Impl_->SceneDisplayRegion = nullptr; + Impl_->GraphicsEngineHandle = nullptr; + Impl_->GraphicsWindowHandle = nullptr; + Impl_->WindowFrameworkHandle = nullptr; + Impl_->Framework = nullptr; + Impl_->Window = nullptr; + Impl_->Initialized = false; } -void MetaCoreRenderDevice::BeginFrame(int width, int height, const glm::vec4& clearColor) const { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, width, height); - Clear(clearColor); +void MetaCoreRenderDevice::RenderFrame() const { + if (Impl_->GraphicsEngineHandle != nullptr) { + Impl_->GraphicsEngineHandle->render_frame(); + } } -void MetaCoreRenderDevice::Clear(const glm::vec4& clearColor) const { - glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +void MetaCoreRenderDevice::PresentFrame() const { + if (Impl_->GraphicsEngineHandle != nullptr) { + Impl_->GraphicsEngineHandle->flip_frame(); + } } -bool MetaCoreRenderDevice::IsInitialized() const { - return Initialized_; +void MetaCoreRenderDevice::SetSceneViewportRect(const MetaCoreViewportRect& viewportRect) { + if (Impl_->SceneDisplayRegion == nullptr || Impl_->Window == nullptr) { + return; + } + + const auto [framebufferWidth, framebufferHeight] = Impl_->Window->GetFramebufferSize(); + if (framebufferWidth <= 0 || framebufferHeight <= 0 || viewportRect.Width <= 1.0F || viewportRect.Height <= 1.0F) { + Impl_->SceneDisplayRegion->set_active(false); + return; + } + + const float clampedLeft = std::clamp(viewportRect.Left / static_cast(framebufferWidth), 0.0F, 1.0F); + const float clampedRight = std::clamp((viewportRect.Left + viewportRect.Width) / static_cast(framebufferWidth), 0.0F, 1.0F); + const float clampedTop = std::clamp(viewportRect.Top / static_cast(framebufferHeight), 0.0F, 1.0F); + const float clampedBottom = std::clamp((viewportRect.Top + viewportRect.Height) / static_cast(framebufferHeight), 0.0F, 1.0F); + + Impl_->SceneDisplayRegion->set_active(true); + Impl_->SceneDisplayRegion->set_dimensions( + clampedLeft, + clampedRight, + 1.0F - clampedBottom, + 1.0F - clampedTop + ); +} + +void* MetaCoreRenderDevice::GetNativeWindowFrameworkHandle() const { + return Impl_->WindowFrameworkHandle; +} + +void* MetaCoreRenderDevice::GetNativeSceneRootHandle() const { + return Impl_->SceneRoot.is_empty() ? nullptr : static_cast(&Impl_->SceneRoot); +} + +void* MetaCoreRenderDevice::GetNativeEditorCameraHandle() const { + return Impl_->EditorCamera.is_empty() ? nullptr : static_cast(&Impl_->EditorCamera); } } // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp b/Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp deleted file mode 100644 index 386d27a..0000000 --- a/Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "MetaCoreRender/MetaCoreSceneRenderer.h" - -#include "MetaCoreRender/MetaCoreDebugGeometry.h" -#include "MetaCoreRender/MetaCoreShaderProgram.h" -#include "MetaCoreScene/MetaCoreScene.h" - -#include -#include - -#include -#include - -namespace MetaCore { - -class MetaCoreSceneRenderer::MetaCoreSceneRendererImpl { -public: - MetaCoreDebugGeometry DebugGeometry{}; - MetaCoreShaderProgram LineShader{}; - MetaCoreShaderProgram LitShader{}; -}; - -namespace { - -glm::mat4 MetaCoreBuildTransformMatrix(const MetaCoreTransformComponent& transform) { - glm::mat4 model(1.0F); - model = glm::translate(model, transform.Position); - model = glm::rotate(model, glm::radians(transform.RotationEulerDegrees.x), glm::vec3(1.0F, 0.0F, 0.0F)); - model = glm::rotate(model, glm::radians(transform.RotationEulerDegrees.y), glm::vec3(0.0F, 1.0F, 0.0F)); - model = glm::rotate(model, glm::radians(transform.RotationEulerDegrees.z), glm::vec3(0.0F, 0.0F, 1.0F)); - model = glm::scale(model, transform.Scale); - return model; -} - -glm::vec3 MetaCoreResolveLightDirection(const MetaCoreScene& scene) { - for (const MetaCoreGameObject& object : scene.GetGameObjects()) { - if (object.Light.has_value()) { - glm::mat4 rotation(1.0F); - rotation = glm::rotate(rotation, glm::radians(object.Transform.RotationEulerDegrees.x), glm::vec3(1.0F, 0.0F, 0.0F)); - rotation = glm::rotate(rotation, glm::radians(object.Transform.RotationEulerDegrees.y), glm::vec3(0.0F, 1.0F, 0.0F)); - rotation = glm::rotate(rotation, glm::radians(object.Transform.RotationEulerDegrees.z), glm::vec3(0.0F, 0.0F, 1.0F)); - return glm::normalize(glm::vec3(rotation * glm::vec4(0.15F, -1.0F, -0.35F, 0.0F))); - } - } - return glm::normalize(glm::vec3(0.15F, -1.0F, -0.35F)); -} - -float MetaCoreResolveLightIntensity(const MetaCoreScene& scene) { - for (const MetaCoreGameObject& object : scene.GetGameObjects()) { - if (object.Light.has_value()) { - return object.Light->Intensity; - } - } - return 1.5F; -} - -glm::vec3 MetaCoreResolveLightColor(const MetaCoreScene& scene) { - for (const MetaCoreGameObject& object : scene.GetGameObjects()) { - if (object.Light.has_value()) { - return object.Light->Color; - } - } - return glm::vec3(1.0F, 1.0F, 1.0F); -} - -} // namespace - -bool MetaCoreSceneRenderer::Initialize() { - Shutdown(); - - Impl_ = new MetaCoreSceneRendererImpl(); - if (!Impl_->DebugGeometry.Initialize()) { - Shutdown(); - return false; - } - - std::string errorMessage; - - const std::string lineVertexShader = R"( - #version 330 core - layout (location = 0) in vec3 aPosition; - layout (location = 2) in vec4 aColor; - - uniform mat4 uView; - uniform mat4 uProjection; - uniform mat4 uModel; - - out vec4 vColor; - - void main() { - vColor = aColor; - gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0); - } - )"; - - const std::string lineFragmentShader = R"( - #version 330 core - in vec4 vColor; - out vec4 FragColor; - - void main() { - FragColor = vColor; - } - )"; - - const std::string litVertexShader = R"( - #version 330 core - layout (location = 0) in vec3 aPosition; - layout (location = 1) in vec3 aNormal; - - uniform mat4 uView; - uniform mat4 uProjection; - uniform mat4 uModel; - - out vec3 vWorldPosition; - out vec3 vWorldNormal; - - void main() { - vec4 worldPosition = uModel * vec4(aPosition, 1.0); - vWorldPosition = worldPosition.xyz; - vWorldNormal = normalize(mat3(transpose(inverse(uModel))) * aNormal); - gl_Position = uProjection * uView * worldPosition; - } - )"; - - const std::string litFragmentShader = R"( - #version 330 core - in vec3 vWorldPosition; - in vec3 vWorldNormal; - - uniform vec3 uBaseColor; - uniform vec3 uLightDirection; - uniform vec3 uLightColor; - uniform float uLightIntensity; - - out vec4 FragColor; - - void main() { - vec3 normal = normalize(vWorldNormal); - vec3 lightDirection = normalize(-uLightDirection); - float diffuse = max(dot(normal, lightDirection), 0.0); - vec3 ambient = uBaseColor * 0.28; - vec3 lighting = ambient + (uBaseColor * uLightColor * diffuse * uLightIntensity); - FragColor = vec4(lighting, 1.0); - } - )"; - - if (!Impl_->LineShader.BuildFromSource(lineVertexShader, lineFragmentShader, errorMessage)) { - Shutdown(); - return false; - } - - if (!Impl_->LitShader.BuildFromSource(litVertexShader, litFragmentShader, errorMessage)) { - Shutdown(); - return false; - } - - return true; -} - -void MetaCoreSceneRenderer::Shutdown() { - if (Impl_ != nullptr) { - Impl_->DebugGeometry.Shutdown(); - Impl_->LineShader.Shutdown(); - Impl_->LitShader.Shutdown(); - delete Impl_; - Impl_ = nullptr; - } -} - -void MetaCoreSceneRenderer::RenderScene(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView) const { - if (Impl_ == nullptr) { - return; - } - - Impl_->LineShader.Bind(); - Impl_->LineShader.SetMatrix4("uView", sceneView.ViewMatrix); - Impl_->LineShader.SetMatrix4("uProjection", sceneView.ProjectionMatrix); - Impl_->LineShader.SetMatrix4("uModel", glm::mat4(1.0F)); - Impl_->DebugGeometry.GetGridMesh().Draw(); - Impl_->DebugGeometry.GetAxesMesh().Draw(); - - const glm::vec3 lightDirection = MetaCoreResolveLightDirection(scene); - const glm::vec3 lightColor = MetaCoreResolveLightColor(scene); - const float lightIntensity = MetaCoreResolveLightIntensity(scene); - - Impl_->LitShader.Bind(); - Impl_->LitShader.SetMatrix4("uView", sceneView.ViewMatrix); - Impl_->LitShader.SetMatrix4("uProjection", sceneView.ProjectionMatrix); - Impl_->LitShader.SetVector3("uLightDirection", lightDirection); - Impl_->LitShader.SetVector3("uLightColor", lightColor); - Impl_->LitShader.SetFloat("uLightIntensity", lightIntensity); - - for (const MetaCoreGameObject& object : scene.GetGameObjects()) { - if (!object.MeshRenderer.has_value() || !object.MeshRenderer->Visible) { - continue; - } - - glm::vec3 baseColor = object.MeshRenderer->BaseColor; - if (object.Id == sceneView.SelectedObjectId) { - baseColor = glm::mix(baseColor, glm::vec3(1.0F, 0.62F, 0.18F), 0.55F); - } - - Impl_->LitShader.SetMatrix4("uModel", MetaCoreBuildTransformMatrix(object.Transform)); - Impl_->LitShader.SetVector3("uBaseColor", baseColor); - Impl_->DebugGeometry.GetCubeMesh().Draw(); - } -} - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Private/MetaCoreShaderProgram.cpp b/Source/MetaCoreRender/Private/MetaCoreShaderProgram.cpp deleted file mode 100644 index 7576d67..0000000 --- a/Source/MetaCoreRender/Private/MetaCoreShaderProgram.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "MetaCoreRender/MetaCoreShaderProgram.h" - -#include - -#include - -namespace MetaCore { - -namespace { - -bool MetaCoreCompileShader(unsigned int shaderHandle, const std::string& source, std::string& outError) { - const char* rawSource = source.c_str(); - glShaderSource(shaderHandle, 1, &rawSource, nullptr); - glCompileShader(shaderHandle); - - int compileStatus = 0; - glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileStatus); - if (compileStatus == GL_TRUE) { - return true; - } - - int logLength = 0; - glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, &logLength); - std::vector logBuffer(static_cast((logLength > 1) ? logLength : 1), '\0'); - glGetShaderInfoLog(shaderHandle, logLength, nullptr, logBuffer.data()); - outError.assign(logBuffer.data()); - return false; -} - -} // namespace - -MetaCoreShaderProgram::~MetaCoreShaderProgram() { - Shutdown(); -} - -bool MetaCoreShaderProgram::BuildFromSource(const std::string& vertexSource, const std::string& fragmentSource, std::string& outError) { - Shutdown(); - - const unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); - const unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - if (!MetaCoreCompileShader(vertexShader, vertexSource, outError)) { - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - return false; - } - - if (!MetaCoreCompileShader(fragmentShader, fragmentSource, outError)) { - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - return false; - } - - ProgramHandle_ = glCreateProgram(); - glAttachShader(ProgramHandle_, vertexShader); - glAttachShader(ProgramHandle_, fragmentShader); - glLinkProgram(ProgramHandle_); - - int linkStatus = 0; - glGetProgramiv(ProgramHandle_, GL_LINK_STATUS, &linkStatus); - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - if (linkStatus == GL_TRUE) { - return true; - } - - int logLength = 0; - glGetProgramiv(ProgramHandle_, GL_INFO_LOG_LENGTH, &logLength); - std::vector logBuffer(static_cast((logLength > 1) ? logLength : 1), '\0'); - glGetProgramInfoLog(ProgramHandle_, logLength, nullptr, logBuffer.data()); - outError.assign(logBuffer.data()); - - glDeleteProgram(ProgramHandle_); - ProgramHandle_ = 0; - return false; -} - -void MetaCoreShaderProgram::Shutdown() { - if (ProgramHandle_ != 0) { - glDeleteProgram(ProgramHandle_); - ProgramHandle_ = 0; - } -} - -void MetaCoreShaderProgram::Bind() const { - glUseProgram(ProgramHandle_); -} - -unsigned int MetaCoreShaderProgram::GetNativeHandle() const { - return ProgramHandle_; -} - -void MetaCoreShaderProgram::SetMatrix4(const char* name, const glm::mat4& value) const { - const int location = glGetUniformLocation(ProgramHandle_, name); - glUniformMatrix4fv(location, 1, GL_FALSE, &value[0][0]); -} - -void MetaCoreShaderProgram::SetVector3(const char* name, const glm::vec3& value) const { - const int location = glGetUniformLocation(ProgramHandle_, name); - glUniform3fv(location, 1, &value[0]); -} - -void MetaCoreShaderProgram::SetFloat(const char* name, float value) const { - const int location = glGetUniformLocation(ProgramHandle_, name); - glUniform1f(location, value); -} - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreDebugGeometry.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreDebugGeometry.h deleted file mode 100644 index 27b6043..0000000 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreDebugGeometry.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "MetaCoreRender/MetaCoreMesh.h" - -namespace MetaCore { - -// 负责构建第一阶段需要的内置几何体。 -class MetaCoreDebugGeometry { -public: - // 创建网格、坐标轴和立方体三类内置几何。 - bool Initialize(); - - // 释放全部几何资源。 - void Shutdown(); - - // 返回地面网格。 - [[nodiscard]] const MetaCoreMesh& GetGridMesh() const; - - // 返回坐标轴。 - [[nodiscard]] const MetaCoreMesh& GetAxesMesh() const; - - // 返回立方体。 - [[nodiscard]] const MetaCoreMesh& GetCubeMesh() const; - -private: - MetaCoreMesh GridMesh_{}; - MetaCoreMesh AxesMesh_{}; - MetaCoreMesh CubeMesh_{}; -}; - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreEditorViewportRenderer.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreEditorViewportRenderer.h index c2349e9..fc2f1d1 100644 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreEditorViewportRenderer.h +++ b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreEditorViewportRenderer.h @@ -1,45 +1,32 @@ #pragma once +#include "MetaCoreRender/MetaCorePandaSceneBridge.h" #include "MetaCoreRender/MetaCoreRenderTypes.h" namespace MetaCore { +class MetaCoreRenderDevice; class MetaCoreScene; -// 管理编辑器场景视口所需的离屏帧缓冲。 +// 管理编辑器中央场景面板与 Panda3D DisplayRegion 之间的同步。 class MetaCoreEditorViewportRenderer { public: - // 初始化离屏渲染器和场景渲染器。 - bool Initialize(); + // 初始化 Panda3D 场景桥接与显示区域驱动。 + bool Initialize(MetaCoreRenderDevice& renderDevice); - // 释放离屏缓冲与场景渲染器资源。 + // 释放桥接层与内部缓存。 void Shutdown(); - // 根据新的视口尺寸重建帧缓冲。 - void Resize(int width, int height); + // 写入当前 Scene 面板像素矩形。 + void SetViewportRect(const MetaCoreViewportRect& viewportRect); - // 将场景渲染到当前离屏纹理中。 + // 将场景状态同步到 Panda3D,并更新编辑器相机。 void RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView); - // 返回颜色纹理句柄。 - [[nodiscard]] unsigned int GetColorTextureHandle() const; - - // 返回视口宽度。 - [[nodiscard]] int GetWidth() const; - - // 返回视口高度。 - [[nodiscard]] int GetHeight() const; - private: - void RebuildFramebuffer(); - void DestroyFramebuffer(); - - unsigned int FramebufferHandle_ = 0; - unsigned int ColorTextureHandle_ = 0; - unsigned int DepthStencilHandle_ = 0; - int Width_ = 1; - int Height_ = 1; - class MetaCoreSceneRenderer* SceneRenderer_ = nullptr; + MetaCoreRenderDevice* RenderDevice_ = nullptr; + MetaCorePandaSceneBridge SceneBridge_{}; + MetaCoreViewportRect ViewportRect_{}; }; } // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreMesh.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreMesh.h deleted file mode 100644 index 32eb7bc..0000000 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreMesh.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -namespace MetaCore { - -// 表示渲染层使用的统一顶点格式。 -struct MetaCoreVertex { - glm::vec3 Position{0.0F, 0.0F, 0.0F}; - glm::vec3 Normal{0.0F, 0.0F, 0.0F}; - glm::vec4 Color{1.0F, 1.0F, 1.0F, 1.0F}; -}; - -// 标识网格的基础绘制模式。 -enum class MetaCorePrimitiveType { - Triangles, - Lines -}; - -// 封装 VAO/VBO/EBO,并对外暴露简单的 Draw 接口。 -class MetaCoreMesh { -public: - MetaCoreMesh() = default; - ~MetaCoreMesh(); - - // 根据给定顶点和索引创建一个 GPU 网格。 - bool Build(const std::vector& vertices, const std::vector& indices, MetaCorePrimitiveType primitiveType); - - // 销毁 GPU 资源。 - void Shutdown(); - - // 提交一次绘制调用。 - void Draw() const; - -private: - unsigned int VertexArrayHandle_ = 0; - unsigned int VertexBufferHandle_ = 0; - unsigned int IndexBufferHandle_ = 0; - std::uint32_t IndexCount_ = 0; - MetaCorePrimitiveType PrimitiveType_ = MetaCorePrimitiveType::Triangles; -}; - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCorePandaSceneBridge.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCorePandaSceneBridge.h new file mode 100644 index 0000000..81084ce --- /dev/null +++ b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCorePandaSceneBridge.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace MetaCore { + +class MetaCoreRenderDevice; +class MetaCoreScene; +struct MetaCoreSceneView; + +// 负责在 MetaCoreScene 与 Panda3D NodePath 场景之间建立同步关系。 +class MetaCorePandaSceneBridge { +public: + MetaCorePandaSceneBridge(); + ~MetaCorePandaSceneBridge(); + + // 准备 Panda3D 场景根节点、调试网格与编辑器相机。 + bool Initialize(MetaCoreRenderDevice& renderDevice); + + // 释放桥接层创建的 Panda3D 节点。 + void Shutdown(); + + // 将 MetaCoreScene 当前状态同步到 Panda3D 场景图。 + void SyncScene(const MetaCoreScene& scene); + + // 更新编辑器相机与当前选中对象高亮状态。 + void ApplySceneView(const MetaCoreSceneView& sceneView); + +private: + class MetaCorePandaSceneBridgeImpl; + std::unique_ptr Impl_{}; +}; + +} // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h index 41ecfea..36097e4 100644 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h +++ b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h @@ -1,31 +1,49 @@ #pragma once -#include +#include "MetaCoreRender/MetaCoreRenderTypes.h" -struct GLFWwindow; +#include namespace MetaCore { -// 负责初始化 glad,并管理当前 OpenGL 上下文的基础状态。 +class MetaCoreEditorViewportRenderer; +class MetaCorePandaSceneBridge; +class MetaCoreWindow; + +// 封装 Panda3D 图形引擎、主窗口和中央场景显示区域。 class MetaCoreRenderDevice { public: - // 初始化 OpenGL 函数加载与默认渲染状态。 - bool Initialize(GLFWwindow* nativeWindow); + MetaCoreRenderDevice(); + ~MetaCoreRenderDevice(); - // 关闭设备并重置初始化状态。 + // 绑定 Panda3D 窗口与图形引擎,准备后续场景渲染。 + bool Initialize(MetaCoreWindow& window); + + // 释放 Panda3D 渲染相关资源。 void Shutdown(); - // 开始绘制默认帧缓冲。 - void BeginFrame(int width, int height, const glm::vec4& clearColor) const; + // 提交 Panda3D 场景绘制。 + void RenderFrame() const; - // 清理默认帧缓冲。 - void Clear(const glm::vec4& clearColor) const; + // 提交当前帧翻转,确保 ImGui 叠加结果显示出来。 + void PresentFrame() const; - // 返回设备是否已初始化。 - [[nodiscard]] bool IsInitialized() const; + // 根据 ImGui 场景面板像素矩形更新 Panda3D DisplayRegion。 + void SetSceneViewportRect(const MetaCoreViewportRect& viewportRect); + + // 返回 WindowFramework 原生对象指针,仅供 Panda3D 桥接层使用。 + [[nodiscard]] void* GetNativeWindowFrameworkHandle() const; + + // 返回场景根节点原生对象指针,仅供 Panda3D 桥接层使用。 + [[nodiscard]] void* GetNativeSceneRootHandle() const; + + // 返回编辑器相机节点原生对象指针,仅供 Panda3D 桥接层使用。 + [[nodiscard]] void* GetNativeEditorCameraHandle() const; private: - bool Initialized_ = false; + class MetaCoreRenderDeviceImpl; + + std::unique_ptr Impl_{}; }; } // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h index bb7fb9a..751785d 100644 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h +++ b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h @@ -2,16 +2,24 @@ #include "MetaCoreFoundation/MetaCoreId.h" -#include #include namespace MetaCore { -// 描述一次场景渲染所需的视图参数。 +// 描述场景在宿主窗口中的像素矩形区域。 +struct MetaCoreViewportRect { + float Left = 0.0F; + float Top = 0.0F; + float Width = 1.0F; + float Height = 1.0F; +}; + +// 描述一次 Panda3D 场景同步所需的相机与选择参数。 struct MetaCoreSceneView { - glm::mat4 ViewMatrix{1.0F}; - glm::mat4 ProjectionMatrix{1.0F}; - glm::vec3 CameraPosition{0.0F, 0.0F, 0.0F}; + glm::vec3 CameraPosition{0.0F, 2.2F, 6.5F}; + glm::vec3 CameraTarget{0.0F, 0.7F, 0.0F}; + glm::vec3 CameraUp{0.0F, 1.0F, 0.0F}; + float VerticalFieldOfViewDegrees = 60.0F; MetaCoreId SelectedObjectId = 0; }; diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreSceneRenderer.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreSceneRenderer.h deleted file mode 100644 index 4e99525..0000000 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreSceneRenderer.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "MetaCoreRender/MetaCoreRenderTypes.h" - -namespace MetaCore { - -class MetaCoreScene; - -// 负责把 MetaCoreScene 中的对象绘制到当前激活的 OpenGL 目标上。 -class MetaCoreSceneRenderer { -public: - // 初始化 shader 和内置几何资源。 - bool Initialize(); - - // 释放渲染器创建的 GPU 资源。 - void Shutdown(); - - // 根据给定场景和视图参数提交绘制。 - void RenderScene(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView) const; - -private: - class MetaCoreSceneRendererImpl; - MetaCoreSceneRendererImpl* Impl_ = nullptr; -}; - -} // namespace MetaCore diff --git a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreShaderProgram.h b/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreShaderProgram.h deleted file mode 100644 index ac5f899..0000000 --- a/Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreShaderProgram.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace MetaCore { - -// 封装最基础的 OpenGL Shader Program 生命周期和常用 uniform 设置。 -class MetaCoreShaderProgram { -public: - MetaCoreShaderProgram() = default; - ~MetaCoreShaderProgram(); - - // 根据传入的顶点和片元源码创建程序对象。 - bool BuildFromSource(const std::string& vertexSource, const std::string& fragmentSource, std::string& outError); - - // 销毁当前程序对象。 - void Shutdown(); - - // 绑定当前 shader program。 - void Bind() const; - - // 返回当前程序句柄。 - [[nodiscard]] unsigned int GetNativeHandle() const; - - // 设置 mat4 uniform。 - void SetMatrix4(const char* name, const glm::mat4& value) const; - - // 设置 vec3 uniform。 - void SetVector3(const char* name, const glm::vec3& value) const; - - // 设置 float uniform。 - void SetFloat(const char* name, float value) const; - -private: - unsigned int ProgramHandle_ = 0; -}; - -} // namespace MetaCore diff --git a/TestProject/Assets/Materials/default_pbr.material.json b/TestProject/Assets/Materials/default_pbr.material.json new file mode 100644 index 0000000..3d8836b --- /dev/null +++ b/TestProject/Assets/Materials/default_pbr.material.json @@ -0,0 +1,7 @@ +{ + "name": "DefaultPbr", + "shader_family": "simplepbr", + "base_color": [1.0, 1.0, 1.0, 1.0], + "roughness": 1.0, + "metallic": 0.0 +} diff --git a/TestProject/Assets/Materials/default_pbr.material.json.meta b/TestProject/Assets/Materials/default_pbr.material.json.meta new file mode 100644 index 0000000..8bcf0f2 --- /dev/null +++ b/TestProject/Assets/Materials/default_pbr.material.json.meta @@ -0,0 +1,5 @@ +{ + "id": "00005052332aa8d4625dd7775e94e6d800000005", + "relative_path": "Assets/Materials/default_pbr.material.json", + "type": "material" +} \ No newline at end of file diff --git a/TestProject/Assets/UI/main_menu.rcss b/TestProject/Assets/UI/main_menu.rcss new file mode 100644 index 0000000..c46e6b4 --- /dev/null +++ b/TestProject/Assets/UI/main_menu.rcss @@ -0,0 +1,10 @@ +body { + font-family: sans-serif; + color: #f2f4f8; +} +.root-panel { + width: 420px; + margin: 40px auto; + padding: 24px; + background: rgba(16, 18, 24, 0.85); +} diff --git a/TestProject/Assets/UI/main_menu.rcss.meta b/TestProject/Assets/UI/main_menu.rcss.meta new file mode 100644 index 0000000..7fa65bc --- /dev/null +++ b/TestProject/Assets/UI/main_menu.rcss.meta @@ -0,0 +1,5 @@ +{ + "id": "00005052332a9f74171e39271225dd0800000004", + "relative_path": "Assets/UI/main_menu.rcss", + "type": "ui_stylesheet" +} \ No newline at end of file diff --git a/TestProject/Assets/UI/main_menu.rml b/TestProject/Assets/UI/main_menu.rml new file mode 100644 index 0000000..8d9a751 --- /dev/null +++ b/TestProject/Assets/UI/main_menu.rml @@ -0,0 +1,11 @@ + + + + + +
+

MetaCore

+

Runtime UI scaffold

+
+ +
diff --git a/TestProject/Assets/UI/main_menu.rml.meta b/TestProject/Assets/UI/main_menu.rml.meta new file mode 100644 index 0000000..9001f47 --- /dev/null +++ b/TestProject/Assets/UI/main_menu.rml.meta @@ -0,0 +1,5 @@ +{ + "id": "00005052332a822841724324849eccb900000003", + "relative_path": "Assets/UI/main_menu.rml", + "type": "ui_document" +} \ No newline at end of file diff --git a/TestProject/Library/AssetDB.json b/TestProject/Library/AssetDB.json new file mode 100644 index 0000000..872f886 --- /dev/null +++ b/TestProject/Library/AssetDB.json @@ -0,0 +1,19 @@ +{ + "records": [ + { + "id": "00005052332a822841724324849eccb900000003", + "relative_path": "Assets/UI/main_menu.rml", + "type": "ui_document" + }, + { + "id": "00005052332a9f74171e39271225dd0800000004", + "relative_path": "Assets/UI/main_menu.rcss", + "type": "ui_stylesheet" + }, + { + "id": "00005052332aa8d4625dd7775e94e6d800000005", + "relative_path": "Assets/Materials/default_pbr.material.json", + "type": "material" + } + ] +} \ No newline at end of file diff --git a/TestProject/Library/Layout/editor_layout.json b/TestProject/Library/Layout/editor_layout.json new file mode 100644 index 0000000..091d47b --- /dev/null +++ b/TestProject/Library/Layout/editor_layout.json @@ -0,0 +1,9 @@ +{ + "layout_name": "Default", + "hierarchy_visible": true, + "inspector_visible": true, + "project_visible": true, + "console_visible": true, + "runtime_preview_visible": true, + "toolbar_visible": true +} diff --git a/TestProject/MetaCore.project.json b/TestProject/MetaCore.project.json new file mode 100644 index 0000000..ad7e563 --- /dev/null +++ b/TestProject/MetaCore.project.json @@ -0,0 +1,8 @@ +{ + "name": "MetaCoreTest", + "scenes": [ + "Scenes/Main.mcscene.json" + ], + "startup_scene": "Scenes/Main.mcscene.json", + "version": "0.1.0" +} \ No newline at end of file diff --git a/TestProject/Scenes/Main.mcscene.json b/TestProject/Scenes/Main.mcscene.json new file mode 100644 index 0000000..c888922 --- /dev/null +++ b/TestProject/Scenes/Main.mcscene.json @@ -0,0 +1,76 @@ +{ + "name": "Main", + "objects": [ + { + "camera": { + "far_clip": 1000, + "fov_degrees": 60, + "near_clip": 0.100000001490116, + "primary": true + }, + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "0000505233216b341f8e0361195336fe00000001", + "name": "Main Camera", + "parent_id": "", + "transform": { + "position": [ + 0, + -10, + 3 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005052332197bcd649b574240bc6be00000002", + "light": { + "color": [ + 1, + 1, + 1 + ], + "intensity": 1, + "range": 10, + "spot_angle_degrees": 45, + "type": "directional" + }, + "name": "Directional Light", + "parent_id": "", + "transform": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + } + ] +} \ No newline at end of file diff --git a/TestProject/Scenes/Test.mcscene.json b/TestProject/Scenes/Test.mcscene.json new file mode 100644 index 0000000..f29431f --- /dev/null +++ b/TestProject/Scenes/Test.mcscene.json @@ -0,0 +1,108 @@ +{ + "name": "Main", + "objects": [ + { + "camera": { + "far_clip": 1000, + "fov_degrees": 60, + "near_clip": 0.100000001490116, + "primary": true + }, + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005052333cdf54bd42defb639e412c00000006", + "name": "Main Camera", + "parent_id": "", + "transform": { + "position": [ + 0, + -10, + 3 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005052333ceef49f76de9c4d0fd70200000007", + "light": { + "color": [ + 1, + 1, + 1 + ], + "intensity": 1, + "range": 10, + "spot_angle_degrees": 45, + "type": "directional" + }, + "name": "Directional Light", + "parent_id": "", + "transform": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "editor_metadata": { + "editor_only": false, + "locked": false, + "selected": false + }, + "id": "00005052333cf6c426b72f1a10f785ee00000008", + "mesh_renderer": { + "material_asset_id": "", + "mesh_asset_id": "mesh.cube", + "visible": true + }, + "name": "Cube", + "parent_id": "", + "transform": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + } + ] +} \ No newline at end of file diff --git a/cmake/MetaCorePanda3D.cmake b/cmake/MetaCorePanda3D.cmake new file mode 100644 index 0000000..f2b64d9 --- /dev/null +++ b/cmake/MetaCorePanda3D.cmake @@ -0,0 +1,114 @@ +set(METACORE_PANDA3D_VERSION "1.10.16" CACHE STRING "Pinned Panda3D SDK version used by MetaCore") +set(METACORE_PANDA3D_ARCH "x64" CACHE STRING "Pinned Panda3D Windows architecture used by MetaCore") +set(METACORE_PANDA3D_LOCAL_ROOT "${CMAKE_SOURCE_DIR}/.metacore/deps/panda3d/${METACORE_PANDA3D_VERSION}-${METACORE_PANDA3D_ARCH}" CACHE PATH "Local Panda3D SDK cache directory") + +function(metacore_prepare_panda3d) + if(WIN32) + if(DEFINED ENV{PANDA3D_ROOT} AND NOT "$ENV{PANDA3D_ROOT}" STREQUAL "") + set(_metacore_panda3d_root "$ENV{PANDA3D_ROOT}") + elseif(DEFINED PANDA3D_ROOT AND NOT "${PANDA3D_ROOT}" STREQUAL "") + set(_metacore_panda3d_root "${PANDA3D_ROOT}") + else() + set(_metacore_panda3d_root "${METACORE_PANDA3D_LOCAL_ROOT}") + endif() + + file(TO_CMAKE_PATH "${_metacore_panda3d_root}" _metacore_panda3d_root) + + if(NOT EXISTS "${_metacore_panda3d_root}/include/pandaFramework.h") + if(METACORE_AUTO_PREPARE_PANDA3D) + message(STATUS "MetaCore will prepare Panda3D SDK into ${_metacore_panda3d_root}") + execute_process( + COMMAND + powershell + -NoProfile + -ExecutionPolicy Bypass + -File "${CMAKE_SOURCE_DIR}/scripts/PrepareMetaCorePanda3D.ps1" + -Version "${METACORE_PANDA3D_VERSION}" + -Architecture "${METACORE_PANDA3D_ARCH}" + -InstallDir "${_metacore_panda3d_root}" + RESULT_VARIABLE _metacore_prepare_result + ) + if(NOT _metacore_prepare_result EQUAL 0) + message(FATAL_ERROR "MetaCore failed to prepare Panda3D SDK. Set PANDA3D_ROOT manually or inspect scripts/PrepareMetaCorePanda3D.ps1 output.") + endif() + else() + message(FATAL_ERROR "Panda3D SDK was not found. Set PANDA3D_ROOT or enable METACORE_AUTO_PREPARE_PANDA3D.") + endif() + endif() + + set(METACORE_PANDA3D_ROOT "${_metacore_panda3d_root}" CACHE PATH "Resolved Panda3D SDK root used by MetaCore" FORCE) + set(METACORE_PANDA3D_INCLUDE_DIR "${METACORE_PANDA3D_ROOT}/include" CACHE PATH "Resolved Panda3D include directory" FORCE) + set(METACORE_PANDA3D_LIB_DIR "${METACORE_PANDA3D_ROOT}/lib" CACHE PATH "Resolved Panda3D library directory" FORCE) + set(METACORE_PANDA3D_BIN_DIR "${METACORE_PANDA3D_ROOT}/bin" CACHE PATH "Resolved Panda3D runtime directory" FORCE) + set(METACORE_PANDA3D_ETC_DIR "${METACORE_PANDA3D_ROOT}/etc" CACHE PATH "Resolved Panda3D config directory" FORCE) + set(METACORE_PANDA3D_MODELS_DIR "${METACORE_PANDA3D_ROOT}/models" CACHE PATH "Resolved Panda3D models directory" FORCE) + set(METACORE_PANDA3D_PLUGINS_DIR "${METACORE_PANDA3D_ROOT}/plugins" CACHE PATH "Resolved Panda3D plugins directory" FORCE) + + set(_metacore_panda3d_libraries + "${METACORE_PANDA3D_LIB_DIR}/libp3framework.lib" + "${METACORE_PANDA3D_LIB_DIR}/libpanda.lib" + "${METACORE_PANDA3D_LIB_DIR}/libpandafx.lib" + "${METACORE_PANDA3D_LIB_DIR}/libpandaexpress.lib" + "${METACORE_PANDA3D_LIB_DIR}/libpandagl.lib" + "${METACORE_PANDA3D_LIB_DIR}/libp3windisplay.lib" + "${METACORE_PANDA3D_LIB_DIR}/libp3dtool.lib" + "${METACORE_PANDA3D_LIB_DIR}/libp3dtoolconfig.lib" + opengl32 + gdi32 + user32 + shell32 + advapi32 + ws2_32 + winmm + ) + + add_library(MetaCorePanda3D::SDK INTERFACE IMPORTED GLOBAL) + set_target_properties(MetaCorePanda3D::SDK PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${METACORE_PANDA3D_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${_metacore_panda3d_libraries}" + ) + + file(GLOB METACORE_PANDA3D_RUNTIME_DLLS "${METACORE_PANDA3D_BIN_DIR}/*.dll") + set(METACORE_PANDA3D_RUNTIME_DLLS "${METACORE_PANDA3D_RUNTIME_DLLS}" CACHE INTERNAL "Resolved Panda3D runtime DLL list") + else() + message(FATAL_ERROR "MetaCore Panda3D V1 currently supports Windows only.") + endif() +endfunction() + +function(metacore_stage_panda3d_runtime target_name) + if(NOT TARGET ${target_name}) + message(FATAL_ERROR "Target ${target_name} does not exist.") + endif() + + foreach(_metacore_runtime_dll IN LISTS METACORE_PANDA3D_RUNTIME_DLLS) + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${_metacore_runtime_dll}" + "$" + ) + endforeach() + + if(EXISTS "${METACORE_PANDA3D_ETC_DIR}") + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${METACORE_PANDA3D_ETC_DIR}" + "$/etc" + ) + endif() + + if(EXISTS "${METACORE_PANDA3D_MODELS_DIR}") + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${METACORE_PANDA3D_MODELS_DIR}" + "$/models" + ) + endif() + + if(EXISTS "${METACORE_PANDA3D_PLUGINS_DIR}") + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${METACORE_PANDA3D_PLUGINS_DIR}" + "$/plugins" + ) + endif() +endfunction() diff --git a/scripts/PrepareMetaCorePanda3D.ps1 b/scripts/PrepareMetaCorePanda3D.ps1 new file mode 100644 index 0000000..afeb15c --- /dev/null +++ b/scripts/PrepareMetaCorePanda3D.ps1 @@ -0,0 +1,60 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Version, + + [Parameter(Mandatory = $true)] + [string]$Architecture, + + [Parameter(Mandatory = $true)] + [string]$InstallDir +) + +$ErrorActionPreference = "Stop" + +if (Test-Path (Join-Path $InstallDir "include\\pandaFramework.h")) { + Write-Host "MetaCore Panda3D SDK already prepared at $InstallDir" + exit 0 +} + +$installParent = Split-Path -Parent $InstallDir +New-Item -ItemType Directory -Force -Path $installParent | Out-Null + +$downloadCacheDir = Join-Path $PSScriptRoot "..\\.metacore\\downloads" +New-Item -ItemType Directory -Force -Path $downloadCacheDir | Out-Null + +$installerName = "Panda3D-SDK-$Version-$Architecture.exe" +$installerPath = Join-Path $downloadCacheDir $installerName +$downloadUrl = "https://www.panda3d.org/download/panda3d-$Version/$installerName" + +if (-not (Test-Path $installerPath)) { + Write-Host "MetaCore downloading Panda3D SDK from $downloadUrl" + & curl.exe -L --fail --output $installerPath $downloadUrl + if ($LASTEXITCODE -ne 0) { + throw "MetaCore failed to download Panda3D SDK." + } +} + +if (Test-Path $InstallDir) { + Remove-Item -Recurse -Force $InstallDir +} + +New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null + +$installDirFullPath = (Resolve-Path $InstallDir).Path +Write-Host "MetaCore installing Panda3D SDK into $installDirFullPath" + +$installerLaunchPath = Join-Path $downloadCacheDir ("launch-" + $installerName) +Copy-Item -Force $installerPath $installerLaunchPath + +$installProcess = Start-Process -FilePath $installerLaunchPath -ArgumentList @("/S", "/D=$installDirFullPath") -Wait -PassThru +if ($installProcess.ExitCode -ne 0) { + throw "MetaCore Panda3D installer failed with exit code $($installProcess.ExitCode)." +} + +Remove-Item -Force $installerLaunchPath -ErrorAction SilentlyContinue + +if (-not (Test-Path (Join-Path $installDirFullPath "include\\pandaFramework.h"))) { + throw "MetaCore Panda3D installation finished but expected headers were not found." +} + +Write-Host "MetaCore Panda3D SDK is ready at $installDirFullPath" diff --git a/vcpkg.json b/vcpkg.json index f3a2ec6..616fbfa 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,20 +2,13 @@ "name": "metacore", "version-string": "1.0.0", "dependencies": [ - { - "name": "glad", - "features": [ - "gl-api-33" - ] - }, - "glfw3", "glm", { "name": "imgui", "default-features": false, "features": [ "docking-experimental", - "glfw-binding", + "win32-binding", "opengl3-binding" ] }