Rebuild MetaCore editor on Panda3D with single-window viewport
This commit is contained in:
parent
a637100607
commit
633156e3be
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
build/
|
||||
vcpkg_installed/
|
||||
downloads/
|
||||
.metacore/
|
||||
.vs/
|
||||
CMakeUserPresets.json
|
||||
imgui.ini
|
||||
|
||||
@ -1,8 +1,16 @@
|
||||
#include "MetaCoreEditor/MetaCoreEditorApp.h"
|
||||
|
||||
int main() {
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
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<float>(windowWidth),
|
||||
static_cast<float>(windowHeight)
|
||||
});
|
||||
viewportRenderer.RenderSceneToViewport(scene, MetaCoreBuildPlayerSceneView());
|
||||
renderDevice.RenderFrame();
|
||||
renderDevice.PresentFrame();
|
||||
window.EndFrame();
|
||||
}
|
||||
|
||||
viewportRenderer.Shutdown();
|
||||
renderDevice.Shutdown();
|
||||
window.Shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
114
CMakeLists.txt
114
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$<$<CONFIG:Debug>: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"
|
||||
"$<TARGET_FILE_DIR:${target_name}>"
|
||||
)
|
||||
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()
|
||||
|
||||
@ -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"
|
||||
|
||||
42
README.md
42
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` 相机交互
|
||||
- 模块注册接口与内置编辑器模块
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "00005031af6c28bc73f3772350037bcf00000005",
|
||||
"relative_path": "Assets/Materials/default_pbr.material.json",
|
||||
"type": "material"
|
||||
}
|
||||
10
SandboxProject/Assets/UI/main_menu.rcss
Normal file
10
SandboxProject/Assets/UI/main_menu.rcss
Normal file
@ -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);
|
||||
}
|
||||
5
SandboxProject/Assets/UI/main_menu.rcss.meta
Normal file
5
SandboxProject/Assets/UI/main_menu.rcss.meta
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "00005031af6c1e30843b82e4691e8cba00000004",
|
||||
"relative_path": "Assets/UI/main_menu.rcss",
|
||||
"type": "ui_stylesheet"
|
||||
}
|
||||
11
SandboxProject/Assets/UI/main_menu.rml
Normal file
11
SandboxProject/Assets/UI/main_menu.rml
Normal file
@ -0,0 +1,11 @@
|
||||
<rml>
|
||||
<head>
|
||||
<link type="text/rcss" href="main_menu.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="root-panel">
|
||||
<h1>MetaCore</h1>
|
||||
<p>Runtime UI scaffold</p>
|
||||
</div>
|
||||
</body>
|
||||
</rml>
|
||||
5
SandboxProject/Assets/UI/main_menu.rml.meta
Normal file
5
SandboxProject/Assets/UI/main_menu.rml.meta
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "00005031af6bf9783f1fb78dcaa5ed8900000003",
|
||||
"relative_path": "Assets/UI/main_menu.rml",
|
||||
"type": "ui_document"
|
||||
}
|
||||
19
SandboxProject/Library/AssetDB.json
Normal file
19
SandboxProject/Library/AssetDB.json
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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
|
||||
9
SandboxProject/Library/Layout/editor_layout.json
Normal file
9
SandboxProject/Library/Layout/editor_layout.json
Normal file
@ -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
|
||||
}
|
||||
8
SandboxProject/MetaCore.project.json
Normal file
8
SandboxProject/MetaCore.project.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "MetaCoreSample",
|
||||
"scenes": [
|
||||
"Scenes/Main.mcscene.json"
|
||||
],
|
||||
"startup_scene": "Scenes/Main.mcscene.json",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
108
SandboxProject/Scenes/Main.mcscene.json
Normal file
108
SandboxProject/Scenes/Main.mcscene.json
Normal file
@ -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
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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 <imgui.h>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <array>
|
||||
@ -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<int>(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<int>(viewportSize.x), static_cast<int>(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<void*>(static_cast<intptr_t>(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
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -5,8 +5,13 @@
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imgui_impl_win32.h>
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
@ -14,6 +19,8 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
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<HWND>(nativeWindowHandle),
|
||||
message,
|
||||
static_cast<WPARAM>(wparam),
|
||||
static_cast<LPARAM>(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<ImGuiWindowFlags>(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);
|
||||
|
||||
@ -5,9 +5,8 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/geometric.hpp>
|
||||
#include <glm/trigonometric.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@ -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 {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreEditor/MetaCoreEditorContext.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
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:
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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<MetaCoreIMenuProvider> provider);
|
||||
@ -58,7 +57,6 @@ private:
|
||||
std::unordered_map<std::string, bool> PanelOpenStates_{};
|
||||
};
|
||||
|
||||
// 定义一个可注册到编辑器中的模块生命周期接口。
|
||||
class MetaCoreIModule {
|
||||
public:
|
||||
virtual ~MetaCoreIModule() = default;
|
||||
|
||||
@ -1,53 +1,49 @@
|
||||
#include "MetaCorePlatform/MetaCoreInput.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
void MetaCoreInput::BeginFrame(GLFWwindow* nativeWindow) {
|
||||
void MetaCoreInput::BeginFrame() {
|
||||
PreviousKeyStates_ = CurrentKeyStates_;
|
||||
PreviousMouseStates_ = CurrentMouseStates_;
|
||||
|
||||
for (int key = 0; key < static_cast<int>(CurrentKeyStates_.size()); ++key) {
|
||||
CurrentKeyStates_[static_cast<std::size_t>(key)] = glfwGetKey(nativeWindow, key) == GLFW_PRESS;
|
||||
}
|
||||
|
||||
for (int button = 0; button < static_cast<int>(CurrentMouseStates_.size()); ++button) {
|
||||
CurrentMouseStates_[static_cast<std::size_t>(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<float>(cursorX), static_cast<float>(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<int>(CurrentKeyStates_.size())) {
|
||||
return false;
|
||||
}
|
||||
void MetaCoreInput::SetKeyState(MetaCoreInputKey key, bool isDown) {
|
||||
CurrentKeyStates_[static_cast<std::size_t>(key)] = isDown;
|
||||
}
|
||||
|
||||
void MetaCoreInput::SetMouseButtonState(MetaCoreMouseButton button, bool isDown) {
|
||||
CurrentMouseStates_[static_cast<std::size_t>(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<std::size_t>(key)];
|
||||
}
|
||||
|
||||
bool MetaCoreInput::WasKeyPressed(int key) const {
|
||||
if (key < 0 || key >= static_cast<int>(CurrentKeyStates_.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t index = static_cast<std::size_t>(key);
|
||||
return CurrentKeyStates_[index] && !PreviousKeyStates_[index];
|
||||
bool MetaCoreInput::WasKeyPressed(MetaCoreInputKey key) const {
|
||||
const std::size_t keyIndex = static_cast<std::size_t>(key);
|
||||
return CurrentKeyStates_[keyIndex] && !PreviousKeyStates_[keyIndex];
|
||||
}
|
||||
|
||||
bool MetaCoreInput::IsMouseButtonDown(int button) const {
|
||||
if (button < 0 || button >= static_cast<int>(CurrentMouseStates_.size())) {
|
||||
return false;
|
||||
}
|
||||
bool MetaCoreInput::IsMouseButtonDown(MetaCoreMouseButton button) const {
|
||||
return CurrentMouseStates_[static_cast<std::size_t>(button)];
|
||||
}
|
||||
|
||||
float MetaCoreInput::GetMouseWheelDelta() const {
|
||||
return MouseWheelDelta_;
|
||||
}
|
||||
|
||||
const glm::vec2& MetaCoreInput::GetCursorPosition() const {
|
||||
return CursorPosition_;
|
||||
}
|
||||
|
||||
@ -1,99 +1,259 @@
|
||||
#include "MetaCorePlatform/MetaCoreWindow.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#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 <windows.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
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<HWND>(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<class MetaCoreWindowMessageProc> 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<std::uintptr_t>(wparam), static_cast<std::intptr_t>(lparam));
|
||||
}
|
||||
|
||||
if (msg == WM_MOUSEWHEEL) {
|
||||
Owner_.Input.AddMouseWheelDelta(static_cast<float>(GET_WHEEL_DELTA_WPARAM(wparam)) / static_cast<float>(WHEEL_DELTA));
|
||||
} else if (msg == WM_CLOSE) {
|
||||
Owner_.CloseRequested = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MetaCoreWindow::MetaCoreWindow()
|
||||
: Impl_(std::make_unique<MetaCoreWindowImpl>()) {
|
||||
}
|
||||
|
||||
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<MetaCoreWindowMessageProc>(*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<float>(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<float>(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<float>(cursorPosition.x), static_cast<float>(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<int, int> 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<int, int> 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
|
||||
|
||||
@ -4,38 +4,72 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
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<bool, 512> CurrentKeyStates_{};
|
||||
std::array<bool, 512> PreviousKeyStates_{};
|
||||
std::array<bool, 8> CurrentMouseStates_{};
|
||||
std::array<bool, 8> PreviousMouseStates_{};
|
||||
static constexpr std::size_t KeyCount_ = static_cast<std::size_t>(MetaCoreInputKey::Count);
|
||||
static constexpr std::size_t MouseButtonCount_ = static_cast<std::size_t>(MetaCoreMouseButton::Count);
|
||||
|
||||
std::array<bool, KeyCount_> CurrentKeyStates_{};
|
||||
std::array<bool, KeyCount_> PreviousKeyStates_{};
|
||||
std::array<bool, MouseButtonCount_> CurrentMouseStates_{};
|
||||
std::array<bool, MouseButtonCount_> 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
|
||||
|
||||
@ -2,55 +2,75 @@
|
||||
|
||||
#include "MetaCorePlatform/MetaCoreInput.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 负责管理主窗口、时间步进和最基础的事件轮询。
|
||||
class MetaCoreRenderDevice;
|
||||
|
||||
// 定义宿主窗口层向上暴露的原生消息回调,用于把 Win32 消息转交给 ImGui。
|
||||
using MetaCoreNativeWindowMessageHandler = std::function<void(void*, unsigned int, std::uintptr_t, std::intptr_t)>;
|
||||
|
||||
// 封装 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<int, int> GetWindowSize() const;
|
||||
|
||||
// 返回帧缓冲尺寸。
|
||||
// 返回当前帧缓冲尺寸。
|
||||
[[nodiscard]] std::pair<int, int> 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<MetaCoreWindowImpl> Impl_{};
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
#include "MetaCoreRender/MetaCoreDebugGeometry.h"
|
||||
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
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<MetaCoreVertex> gridVertices;
|
||||
std::vector<std::uint32_t> 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<float>(step), 0.0F, -static_cast<float>(gridHalfExtent)), glm::vec3(0.0F), lineColor));
|
||||
gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(static_cast<float>(step), 0.0F, static_cast<float>(gridHalfExtent)), glm::vec3(0.0F), lineColor));
|
||||
gridIndices.push_back(gridIndex++);
|
||||
gridIndices.push_back(gridIndex++);
|
||||
|
||||
gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(-static_cast<float>(gridHalfExtent), 0.0F, static_cast<float>(step)), glm::vec3(0.0F), lineColor));
|
||||
gridVertices.push_back(MetaCoreMakeVertex(glm::vec3(static_cast<float>(gridHalfExtent), 0.0F, static_cast<float>(step)), glm::vec3(0.0F), lineColor));
|
||||
gridIndices.push_back(gridIndex++);
|
||||
gridIndices.push_back(gridIndex++);
|
||||
}
|
||||
|
||||
std::vector<MetaCoreVertex> 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<std::uint32_t> axesIndices{0, 1, 2, 3, 4, 5};
|
||||
|
||||
const glm::vec4 cubeColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
std::vector<MetaCoreVertex> 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<std::uint32_t> 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
|
||||
@ -1,116 +1,43 @@
|
||||
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
|
||||
|
||||
#include "MetaCoreRender/MetaCoreSceneRenderer.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
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
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
#include "MetaCoreRender/MetaCoreMesh.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
MetaCoreMesh::~MetaCoreMesh() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool MetaCoreMesh::Build(const std::vector<MetaCoreVertex>& vertices, const std::vector<std::uint32_t>& indices, MetaCorePrimitiveType primitiveType) {
|
||||
Shutdown();
|
||||
|
||||
PrimitiveType_ = primitiveType;
|
||||
IndexCount_ = static_cast<std::uint32_t>(indices.size());
|
||||
|
||||
glGenVertexArrays(1, &VertexArrayHandle_);
|
||||
glGenBuffers(1, &VertexBufferHandle_);
|
||||
glGenBuffers(1, &IndexBufferHandle_);
|
||||
|
||||
glBindVertexArray(VertexArrayHandle_);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferHandle_);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
static_cast<GLsizeiptr>(vertices.size() * sizeof(MetaCoreVertex)),
|
||||
vertices.data(),
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferHandle_);
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
static_cast<GLsizeiptr>(indices.size() * sizeof(std::uint32_t)),
|
||||
indices.data(),
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MetaCoreVertex), reinterpret_cast<const void*>(offsetof(MetaCoreVertex, Position)));
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MetaCoreVertex), reinterpret_cast<const void*>(offsetof(MetaCoreVertex, Normal)));
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MetaCoreVertex), reinterpret_cast<const void*>(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<GLsizei>(IndexCount_),
|
||||
GL_UNSIGNED_INT,
|
||||
nullptr
|
||||
);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
317
Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp
Normal file
317
Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp
Normal file
@ -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 <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/gtx/euler_angles.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
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<float>(lineIndex), 0.0F, static_cast<float>(-gridHalfExtent))));
|
||||
gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(lineIndex), 0.0F, static_cast<float>(gridHalfExtent))));
|
||||
gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(-gridHalfExtent), 0.0F, static_cast<float>(lineIndex))));
|
||||
gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast<float>(gridHalfExtent), 0.0F, static_cast<float>(lineIndex))));
|
||||
}
|
||||
|
||||
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<MetaCoreId, MetaCorePandaObjectState> ObjectStates{};
|
||||
};
|
||||
|
||||
MetaCorePandaSceneBridge::MetaCorePandaSceneBridge()
|
||||
: Impl_(std::make_unique<MetaCorePandaSceneBridgeImpl>()) {
|
||||
}
|
||||
|
||||
MetaCorePandaSceneBridge::~MetaCorePandaSceneBridge() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool MetaCorePandaSceneBridge::Initialize(MetaCoreRenderDevice& renderDevice) {
|
||||
Shutdown();
|
||||
|
||||
auto* windowFrameworkHandle = static_cast<WindowFramework*>(renderDevice.GetNativeWindowFrameworkHandle());
|
||||
auto* sceneRootHandle = static_cast<NodePath*>(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<WindowFramework*>(Impl_->RenderDevice->GetNativeWindowFrameworkHandle());
|
||||
auto* sceneRootHandle = static_cast<NodePath*>(Impl_->RenderDevice->GetNativeSceneRootHandle());
|
||||
if (windowFrameworkHandle == nullptr || sceneRootHandle == nullptr || sceneRootHandle->is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_set<MetaCoreId> 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<NodePath*>(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
|
||||
@ -1,45 +1,170 @@
|
||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#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 <algorithm>
|
||||
#include <memory>
|
||||
|
||||
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<MetaCoreRenderDeviceImpl>()) {
|
||||
}
|
||||
|
||||
MetaCoreRenderDevice::~MetaCoreRenderDevice() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool MetaCoreRenderDevice::Initialize(MetaCoreWindow& window) {
|
||||
if (Impl_->Initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)) == 0) {
|
||||
auto* frameworkHandle = static_cast<PandaFramework*>(window.GetNativeFrameworkHandle());
|
||||
auto* windowFrameworkHandle = static_cast<WindowFramework*>(window.GetNativeWindowFrameworkHandle());
|
||||
auto* graphicsWindowHandle = static_cast<GraphicsWindow*>(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<float>(framebufferWidth), 0.0F, 1.0F);
|
||||
const float clampedRight = std::clamp((viewportRect.Left + viewportRect.Width) / static_cast<float>(framebufferWidth), 0.0F, 1.0F);
|
||||
const float clampedTop = std::clamp(viewportRect.Top / static_cast<float>(framebufferHeight), 0.0F, 1.0F);
|
||||
const float clampedBottom = std::clamp((viewportRect.Top + viewportRect.Height) / static_cast<float>(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<void*>(&Impl_->SceneRoot);
|
||||
}
|
||||
|
||||
void* MetaCoreRenderDevice::GetNativeEditorCameraHandle() const {
|
||||
return Impl_->EditorCamera.is_empty() ? nullptr : static_cast<void*>(&Impl_->EditorCamera);
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
|
||||
@ -1,209 +0,0 @@
|
||||
#include "MetaCoreRender/MetaCoreSceneRenderer.h"
|
||||
|
||||
#include "MetaCoreRender/MetaCoreDebugGeometry.h"
|
||||
#include "MetaCoreRender/MetaCoreShaderProgram.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
@ -1,110 +0,0 @@
|
||||
#include "MetaCoreRender/MetaCoreShaderProgram.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
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<char> logBuffer(static_cast<std::size_t>((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<char> logBuffer(static_cast<std::size_t>((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
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
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<MetaCoreVertex>& vertices, const std::vector<std::uint32_t>& 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
|
||||
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
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<MetaCorePandaSceneBridgeImpl> Impl_{};
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -1,31 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec4.hpp>
|
||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||
|
||||
struct GLFWwindow;
|
||||
#include <memory>
|
||||
|
||||
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<MetaCoreRenderDeviceImpl> Impl_{};
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
|
||||
@ -2,16 +2,24 @@
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
||||
7
TestProject/Assets/Materials/default_pbr.material.json
Normal file
7
TestProject/Assets/Materials/default_pbr.material.json
Normal file
@ -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
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "00005052332aa8d4625dd7775e94e6d800000005",
|
||||
"relative_path": "Assets/Materials/default_pbr.material.json",
|
||||
"type": "material"
|
||||
}
|
||||
10
TestProject/Assets/UI/main_menu.rcss
Normal file
10
TestProject/Assets/UI/main_menu.rcss
Normal file
@ -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);
|
||||
}
|
||||
5
TestProject/Assets/UI/main_menu.rcss.meta
Normal file
5
TestProject/Assets/UI/main_menu.rcss.meta
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "00005052332a9f74171e39271225dd0800000004",
|
||||
"relative_path": "Assets/UI/main_menu.rcss",
|
||||
"type": "ui_stylesheet"
|
||||
}
|
||||
11
TestProject/Assets/UI/main_menu.rml
Normal file
11
TestProject/Assets/UI/main_menu.rml
Normal file
@ -0,0 +1,11 @@
|
||||
<rml>
|
||||
<head>
|
||||
<link type="text/rcss" href="main_menu.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="root-panel">
|
||||
<h1>MetaCore</h1>
|
||||
<p>Runtime UI scaffold</p>
|
||||
</div>
|
||||
</body>
|
||||
</rml>
|
||||
5
TestProject/Assets/UI/main_menu.rml.meta
Normal file
5
TestProject/Assets/UI/main_menu.rml.meta
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "00005052332a822841724324849eccb900000003",
|
||||
"relative_path": "Assets/UI/main_menu.rml",
|
||||
"type": "ui_document"
|
||||
}
|
||||
19
TestProject/Library/AssetDB.json
Normal file
19
TestProject/Library/AssetDB.json
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
TestProject/Library/Layout/editor_layout.json
Normal file
9
TestProject/Library/Layout/editor_layout.json
Normal file
@ -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
|
||||
}
|
||||
8
TestProject/MetaCore.project.json
Normal file
8
TestProject/MetaCore.project.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "MetaCoreTest",
|
||||
"scenes": [
|
||||
"Scenes/Main.mcscene.json"
|
||||
],
|
||||
"startup_scene": "Scenes/Main.mcscene.json",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
76
TestProject/Scenes/Main.mcscene.json
Normal file
76
TestProject/Scenes/Main.mcscene.json
Normal file
@ -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
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
108
TestProject/Scenes/Test.mcscene.json
Normal file
108
TestProject/Scenes/Test.mcscene.json
Normal file
@ -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
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
114
cmake/MetaCorePanda3D.cmake
Normal file
114
cmake/MetaCorePanda3D.cmake
Normal file
@ -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}"
|
||||
"$<TARGET_FILE_DIR:${target_name}>"
|
||||
)
|
||||
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}"
|
||||
"$<TARGET_FILE_DIR:${target_name}>/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}"
|
||||
"$<TARGET_FILE_DIR:${target_name}>/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}"
|
||||
"$<TARGET_FILE_DIR:${target_name}>/plugins"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
60
scripts/PrepareMetaCorePanda3D.ps1
Normal file
60
scripts/PrepareMetaCorePanda3D.ps1
Normal file
@ -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"
|
||||
@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user