Rebuild MetaCore Unity-like prototype
This commit is contained in:
commit
a637100607
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
build/
|
||||
vcpkg_installed/
|
||||
downloads/
|
||||
.vs/
|
||||
CMakeUserPresets.json
|
||||
imgui.ini
|
||||
*.obj
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.lib
|
||||
*.exe
|
||||
*.vcxproj*
|
||||
*.sln
|
||||
*.log
|
||||
12
Apps/MetaCoreEditor/main.cpp
Normal file
12
Apps/MetaCoreEditor/main.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "MetaCoreEditor/MetaCoreEditorApp.h"
|
||||
|
||||
int main() {
|
||||
MetaCore::MetaCoreEditorApp editorApp;
|
||||
if (!editorApp.Initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int exitCode = editorApp.Run();
|
||||
editorApp.Shutdown();
|
||||
return exitCode;
|
||||
}
|
||||
6
Apps/MetaCorePlayer/main.cpp
Normal file
6
Apps/MetaCorePlayer/main.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "MetaCorePlayer 目前保留为后续运行时模块接入入口。\n";
|
||||
return 0;
|
||||
}
|
||||
253
CMakeLists.txt
Normal file
253
CMakeLists.txt
Normal file
@ -0,0 +1,253 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(MetaCore
|
||||
VERSION 1.0.0
|
||||
DESCRIPTION "MetaCore Unity-like editor prototype"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
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(EXISTS "${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-windows/share/glad/gladConfig.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")
|
||||
|
||||
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)
|
||||
|
||||
set(METACORE_FOUNDATION_HEADERS
|
||||
Source/MetaCoreFoundation/Public/MetaCoreFoundation/MetaCoreId.h
|
||||
Source/MetaCoreFoundation/Public/MetaCoreFoundation/MetaCoreLogService.h
|
||||
)
|
||||
|
||||
set(METACORE_FOUNDATION_SOURCES
|
||||
Source/MetaCoreFoundation/Private/MetaCoreId.cpp
|
||||
Source/MetaCoreFoundation/Private/MetaCoreLogService.cpp
|
||||
)
|
||||
|
||||
add_library(MetaCoreFoundation STATIC
|
||||
${METACORE_FOUNDATION_HEADERS}
|
||||
${METACORE_FOUNDATION_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(MetaCoreFoundation
|
||||
PUBLIC
|
||||
Source/MetaCoreFoundation/Public
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(MetaCoreFoundation PRIVATE /W4 /permissive- /EHsc)
|
||||
else()
|
||||
target_compile_options(MetaCoreFoundation PRIVATE -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
set(METACORE_PLATFORM_HEADERS
|
||||
Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreInput.h
|
||||
Source/MetaCorePlatform/Public/MetaCorePlatform/MetaCoreWindow.h
|
||||
)
|
||||
|
||||
set(METACORE_PLATFORM_SOURCES
|
||||
Source/MetaCorePlatform/Private/MetaCoreInput.cpp
|
||||
Source/MetaCorePlatform/Private/MetaCoreWindow.cpp
|
||||
)
|
||||
|
||||
add_library(MetaCorePlatform STATIC
|
||||
${METACORE_PLATFORM_HEADERS}
|
||||
${METACORE_PLATFORM_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(MetaCorePlatform
|
||||
PUBLIC
|
||||
Source/MetaCorePlatform/Public
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCorePlatform
|
||||
PUBLIC
|
||||
MetaCoreFoundation
|
||||
glfw
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(MetaCorePlatform PRIVATE /W4 /permissive- /EHsc)
|
||||
else()
|
||||
target_compile_options(MetaCorePlatform PRIVATE -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
set(METACORE_SCENE_HEADERS
|
||||
Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreComponents.h
|
||||
Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreGameObject.h
|
||||
Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreScene.h
|
||||
)
|
||||
|
||||
set(METACORE_SCENE_SOURCES
|
||||
Source/MetaCoreScene/Private/MetaCoreScene.cpp
|
||||
)
|
||||
|
||||
add_library(MetaCoreScene STATIC
|
||||
${METACORE_SCENE_HEADERS}
|
||||
${METACORE_SCENE_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(MetaCoreScene
|
||||
PUBLIC
|
||||
Source/MetaCoreScene/Public
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCoreScene
|
||||
PUBLIC
|
||||
MetaCoreFoundation
|
||||
glm::glm
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(MetaCoreScene PRIVATE /W4 /permissive- /EHsc)
|
||||
else()
|
||||
target_compile_options(MetaCoreScene PRIVATE -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
add_library(MetaCoreRender STATIC
|
||||
${METACORE_RENDER_HEADERS}
|
||||
${METACORE_RENDER_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(MetaCoreRender
|
||||
PUBLIC
|
||||
Source/MetaCoreRender/Public
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCoreRender
|
||||
PUBLIC
|
||||
MetaCoreFoundation
|
||||
MetaCoreScene
|
||||
MetaCorePlatform
|
||||
OpenGL::GL
|
||||
glad::glad
|
||||
glm::glm
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(MetaCoreRender PRIVATE /W4 /permissive- /EHsc)
|
||||
else()
|
||||
target_compile_options(MetaCoreRender PRIVATE -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
set(METACORE_EDITOR_HEADERS
|
||||
Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorModule.h
|
||||
Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorContext.h
|
||||
Source/MetaCoreEditor/Public/MetaCoreEditor/MetaCoreEditorApp.h
|
||||
)
|
||||
|
||||
set(METACORE_EDITOR_PRIVATE_HEADERS
|
||||
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
|
||||
)
|
||||
|
||||
add_library(MetaCoreEditor STATIC
|
||||
${METACORE_EDITOR_HEADERS}
|
||||
${METACORE_EDITOR_PRIVATE_HEADERS}
|
||||
${METACORE_EDITOR_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(MetaCoreEditor
|
||||
PUBLIC
|
||||
Source/MetaCoreEditor/Public
|
||||
PRIVATE
|
||||
Source/MetaCoreEditor/Private
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCoreEditor
|
||||
PUBLIC
|
||||
MetaCoreFoundation
|
||||
MetaCorePlatform
|
||||
MetaCoreScene
|
||||
MetaCoreRender
|
||||
glm::glm
|
||||
imgui::imgui
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(MetaCoreEditor PRIVATE /W4 /permissive- /EHsc)
|
||||
else()
|
||||
target_compile_options(MetaCoreEditor PRIVATE -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
add_executable(MetaCoreEditorApp
|
||||
Apps/MetaCoreEditor/main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCoreEditorApp
|
||||
PRIVATE
|
||||
MetaCoreEditor
|
||||
)
|
||||
metacore_copy_runtime_dlls(MetaCoreEditorApp)
|
||||
|
||||
add_executable(MetaCorePlayer
|
||||
Apps/MetaCorePlayer/main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCorePlayer
|
||||
PRIVATE
|
||||
MetaCoreFoundation
|
||||
)
|
||||
metacore_copy_runtime_dlls(MetaCorePlayer)
|
||||
|
||||
if(METACORE_BUILD_TESTS)
|
||||
enable_testing()
|
||||
|
||||
add_executable(MetaCoreSmokeTests
|
||||
Tests/MetaCoreSmokeTests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(MetaCoreSmokeTests
|
||||
PRIVATE
|
||||
MetaCoreEditor
|
||||
)
|
||||
metacore_copy_runtime_dlls(MetaCoreSmokeTests)
|
||||
|
||||
add_test(NAME MetaCoreSmokeTests COMMAND MetaCoreSmokeTests)
|
||||
endif()
|
||||
59
CMakePresets.json
Normal file
59
CMakePresets.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"version": 6,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 26,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "base",
|
||||
"hidden": true,
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"toolchainFile": "D:/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_STANDARD": "20",
|
||||
"METACORE_BUILD_TESTS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vs2022-debug",
|
||||
"inherits": "base",
|
||||
"displayName": "VS2022 Debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vs2022-release",
|
||||
"inherits": "base",
|
||||
"displayName": "VS2022 Release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "build-debug",
|
||||
"configurePreset": "vs2022-debug",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "build-release",
|
||||
"configurePreset": "vs2022-release",
|
||||
"configuration": "Release"
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "test-debug",
|
||||
"configurePreset": "vs2022-debug",
|
||||
"configuration": "Debug",
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
50
README.md
Normal file
50
README.md
Normal file
@ -0,0 +1,50 @@
|
||||
# MetaCore
|
||||
|
||||
MetaCore 是一个以 Unity 工作流为参考的纯 C++ 编辑器原型工程。
|
||||
|
||||
## 当前目标
|
||||
|
||||
- 使用 `GLFW + OpenGL + Dear ImGui Docking` 搭建最小可运行编辑器
|
||||
- 使用 `GameObject + Component` 模型组织场景
|
||||
- 先把 `Hierarchy / Scene / Inspector / Project / Console` 跑通
|
||||
- 先体现清晰的渲染架构,再以模块化方式持续增加功能
|
||||
|
||||
## 技术栈
|
||||
|
||||
- `C++20`
|
||||
- `CMake`
|
||||
- `vcpkg`
|
||||
- `GLFW`
|
||||
- `glad`
|
||||
- `OpenGL 3.3`
|
||||
- `glm`
|
||||
- `Dear ImGui Docking`
|
||||
|
||||
## 目录结构
|
||||
|
||||
- `Source/MetaCoreFoundation`:基础服务
|
||||
- `Source/MetaCorePlatform`:窗口与输入
|
||||
- `Source/MetaCoreScene`:场景与对象模型
|
||||
- `Source/MetaCoreRender`:OpenGL 渲染架构
|
||||
- `Source/MetaCoreEditor`:编辑器模块与 Unity-like 界面
|
||||
- `Apps/MetaCoreEditor`:编辑器程序入口
|
||||
- `Apps/MetaCorePlayer`:运行时占位入口
|
||||
- `Tests`:基础烟雾测试
|
||||
|
||||
## 构建
|
||||
|
||||
```powershell
|
||||
cmake --preset vs2022-debug
|
||||
cmake --build --preset build-debug
|
||||
ctest --preset test-debug
|
||||
```
|
||||
|
||||
## 当前完成内容
|
||||
|
||||
- 单窗口 MetaCore 编辑器主循环
|
||||
- 场景视口离屏渲染
|
||||
- 网格、坐标轴、立方体绘制
|
||||
- `Hierarchy` 选择
|
||||
- `Inspector` 中编辑 `Transform`
|
||||
- 轨道/平移/缩放相机控制
|
||||
- 模块注册接口与内置编辑器模块
|
||||
338
Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp
Normal file
338
Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
#include "MetaCoreBuiltinEditorModule.h"
|
||||
|
||||
#include "MetaCoreEditor/MetaCoreEditorContext.h"
|
||||
#include "MetaCoreEditorCameraController.h"
|
||||
#include "MetaCorePlatform/MetaCoreWindow.h"
|
||||
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
namespace {
|
||||
|
||||
void MetaCoreDrawHierarchyNode(MetaCoreEditorContext& editorContext, MetaCoreId objectId) {
|
||||
MetaCoreScene& scene = editorContext.GetScene();
|
||||
MetaCoreGameObject* gameObject = scene.FindGameObject(objectId);
|
||||
if (gameObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<MetaCoreId> childIds = scene.GetChildrenOf(objectId);
|
||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanFullWidth;
|
||||
if (childIds.empty()) {
|
||||
flags |= ImGuiTreeNodeFlags_Leaf;
|
||||
}
|
||||
if (editorContext.GetSelectedObjectId() == objectId) {
|
||||
flags |= ImGuiTreeNodeFlags_Selected;
|
||||
}
|
||||
|
||||
const bool nodeOpened = ImGui::TreeNodeEx(reinterpret_cast<void*>(static_cast<intptr_t>(objectId)), flags, "%s", gameObject->Name.c_str());
|
||||
if (ImGui::IsItemClicked()) {
|
||||
editorContext.SetSelectedObjectId(objectId);
|
||||
editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "Hierarchy", "已选中对象: " + gameObject->Name);
|
||||
}
|
||||
|
||||
if (nodeOpened) {
|
||||
for (MetaCoreId childId : childIds) {
|
||||
MetaCoreDrawHierarchyNode(editorContext, childId);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
class MetaCoreDefaultMenuProvider final : public MetaCoreIMenuProvider {
|
||||
public:
|
||||
std::string GetProviderId() const override { return "MetaCoreDefaultMenuProvider"; }
|
||||
|
||||
void DrawMenuBar(MetaCoreEditorContext& editorContext) override {
|
||||
if (ImGui::BeginMenu("文件")) {
|
||||
if (ImGui::MenuItem("重置布局")) {
|
||||
editorContext.SetDockLayoutBuilt(false);
|
||||
}
|
||||
if (ImGui::MenuItem("退出")) {
|
||||
glfwSetWindowShouldClose(editorContext.GetWindow().GetNativeHandle(), GLFW_TRUE);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("编辑")) {
|
||||
ImGui::MenuItem("撤销", "Ctrl+Z", false, false);
|
||||
ImGui::MenuItem("重做", "Ctrl+Y", false, false);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("资源")) {
|
||||
ImGui::MenuItem("导入资源", nullptr, false, false);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("游戏对象")) {
|
||||
if (ImGui::MenuItem("创建空对象")) {
|
||||
MetaCoreGameObject& object = editorContext.GetScene().CreateGameObject("GameObject");
|
||||
editorContext.SetSelectedObjectId(object.Id);
|
||||
editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "Scene", "已创建空对象");
|
||||
}
|
||||
if (ImGui::MenuItem("创建立方体")) {
|
||||
MetaCoreGameObject& cube = editorContext.GetScene().CreateGameObject("Cube");
|
||||
cube.MeshRenderer = MetaCoreMeshRendererComponent{};
|
||||
cube.Transform.Position = glm::vec3(0.0F, 0.5F, 0.0F);
|
||||
editorContext.SetSelectedObjectId(cube.Id);
|
||||
editorContext.AddConsoleMessage(MetaCoreLogLevel::Info, "Scene", "已创建立方体");
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("组件")) {
|
||||
ImGui::MenuItem("添加组件", nullptr, false, false);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("窗口")) {
|
||||
for (const auto& panelProvider : editorContext.GetModuleRegistry().GetPanelProviders()) {
|
||||
bool& panelOpen = editorContext.GetModuleRegistry().AccessPanelOpenState(panelProvider->GetPanelId());
|
||||
ImGui::MenuItem(panelProvider->GetPanelTitle().c_str(), nullptr, &panelOpen);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("帮助")) {
|
||||
ImGui::MenuItem("MetaCore Unity-like Prototype", nullptr, false, false);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MetaCoreHierarchyPanelProvider final : public MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Hierarchy"; }
|
||||
std::string GetPanelTitle() const override { return "层级"; }
|
||||
bool IsOpenByDefault() const override { return true; }
|
||||
|
||||
void DrawPanel(MetaCoreEditorContext& editorContext) override {
|
||||
ImGui::TextUnformatted("SampleScene");
|
||||
ImGui::Separator();
|
||||
|
||||
for (MetaCoreId rootId : editorContext.GetScene().GetRootObjectIds()) {
|
||||
MetaCoreDrawHierarchyNode(editorContext, rootId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MetaCoreScenePanelProvider final : public MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Scene"; }
|
||||
std::string GetPanelTitle() const override { return "场景"; }
|
||||
bool IsOpenByDefault() const override { return true; }
|
||||
|
||||
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;
|
||||
}
|
||||
if (viewportSize.y < 1.0F) {
|
||||
viewportSize.y = 1.0F;
|
||||
}
|
||||
|
||||
viewportState.Width = viewportSize.x;
|
||||
viewportState.Height = viewportSize.y;
|
||||
|
||||
editorContext.GetViewportRenderer().Resize(static_cast<int>(viewportSize.x), static_cast<int>(viewportSize.y));
|
||||
|
||||
MetaCoreSceneView sceneView;
|
||||
sceneView.ViewMatrix = editorContext.GetCameraController().BuildViewMatrix();
|
||||
sceneView.ProjectionMatrix = editorContext.GetCameraController().BuildProjectionMatrix(viewportSize.x / viewportSize.y);
|
||||
sceneView.CameraPosition = editorContext.GetCameraController().GetCameraPosition();
|
||||
sceneView.SelectedObjectId = editorContext.GetSelectedObjectId();
|
||||
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)
|
||||
);
|
||||
|
||||
viewportState.Hovered = ImGui::IsItemHovered();
|
||||
viewportState.Focused = viewportState.Focused || ImGui::IsItemFocused();
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 28.0F);
|
||||
ImGui::TextDisabled("Alt+左键 环绕 | 中键 平移 | 滚轮 缩放 | F 聚焦");
|
||||
}
|
||||
};
|
||||
|
||||
class MetaCoreProjectPanelProvider final : public MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Project"; }
|
||||
std::string GetPanelTitle() const override { return "项目"; }
|
||||
bool IsOpenByDefault() const override { return true; }
|
||||
|
||||
void DrawPanel(MetaCoreEditorContext&) override {
|
||||
if (ImGui::TreeNodeEx("Assets", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::BulletText("Scenes");
|
||||
ImGui::BulletText("Materials");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNodeEx("Packages", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::TextDisabled("当前阶段未接入真实包管理。");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::TextDisabled("当前无真实资源导入流水线。");
|
||||
}
|
||||
};
|
||||
|
||||
class MetaCoreConsolePanelProvider final : public MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Console"; }
|
||||
std::string GetPanelTitle() const override { return "控制台"; }
|
||||
bool IsOpenByDefault() const override { return true; }
|
||||
|
||||
void DrawPanel(MetaCoreEditorContext& editorContext) override {
|
||||
for (const MetaCoreLogEntry& entry : editorContext.GetLogService().GetEntries()) {
|
||||
ImVec4 textColor = ImVec4(0.85F, 0.85F, 0.88F, 1.0F);
|
||||
if (entry.Level == MetaCoreLogLevel::Warning) {
|
||||
textColor = ImVec4(0.95F, 0.75F, 0.25F, 1.0F);
|
||||
} else if (entry.Level == MetaCoreLogLevel::Error) {
|
||||
textColor = ImVec4(0.95F, 0.35F, 0.30F, 1.0F);
|
||||
}
|
||||
ImGui::TextColored(textColor, "[%s] %s", entry.Category.c_str(), entry.Message.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MetaCoreTransformInspectorDrawer final : public MetaCoreIInspectorDrawer {
|
||||
public:
|
||||
std::string GetDrawerId() const override { return "Transform"; }
|
||||
bool Supports(const MetaCoreGameObject&) const override { return true; }
|
||||
|
||||
void DrawInspector(MetaCoreEditorContext&, MetaCoreGameObject& gameObject) override {
|
||||
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::DragFloat3("Position", glm::value_ptr(gameObject.Transform.Position), 0.05F);
|
||||
ImGui::DragFloat3("Rotation", glm::value_ptr(gameObject.Transform.RotationEulerDegrees), 0.5F);
|
||||
ImGui::DragFloat3("Scale", glm::value_ptr(gameObject.Transform.Scale), 0.05F, 0.05F, 100.0F);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MetaCoreInspectorPanelProvider final : public MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Inspector"; }
|
||||
std::string GetPanelTitle() const override { return "检查器"; }
|
||||
bool IsOpenByDefault() const override { return true; }
|
||||
|
||||
void DrawPanel(MetaCoreEditorContext& editorContext) override {
|
||||
MetaCoreGameObject* selectedObject = editorContext.GetSelectedGameObject();
|
||||
if (selectedObject == nullptr) {
|
||||
ImGui::TextUnformatted("当前没有选中对象。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (BoundObjectId_ != selectedObject->Id) {
|
||||
BoundObjectId_ = selectedObject->Id;
|
||||
NameBuffer_.fill('\0');
|
||||
std::snprintf(NameBuffer_.data(), NameBuffer_.size(), "%s", selectedObject->Name.c_str());
|
||||
}
|
||||
|
||||
ImGui::Text("对象 ID: %llu", static_cast<unsigned long long>(selectedObject->Id));
|
||||
if (ImGui::InputText("名称", NameBuffer_.data(), NameBuffer_.size())) {
|
||||
selectedObject->Name = NameBuffer_.data();
|
||||
}
|
||||
|
||||
if (ImGui::Button("聚焦对象")) {
|
||||
editorContext.GetCameraController().FocusGameObject(*selectedObject);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
for (const auto& drawer : editorContext.GetModuleRegistry().GetInspectorDrawers()) {
|
||||
if (drawer->Supports(*selectedObject)) {
|
||||
drawer->DrawInspector(editorContext, *selectedObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedObject->Camera.has_value()) {
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted("Camera");
|
||||
ImGui::Text("FOV: %.1f", selectedObject->Camera->FieldOfViewDegrees);
|
||||
}
|
||||
|
||||
if (selectedObject->Light.has_value()) {
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted("Light");
|
||||
ImGui::DragFloat("Intensity", &selectedObject->Light->Intensity, 0.05F, 0.0F, 8.0F);
|
||||
}
|
||||
|
||||
if (selectedObject->MeshRenderer.has_value()) {
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted("MeshRenderer");
|
||||
ImGui::ColorEdit3("BaseColor", glm::value_ptr(selectedObject->MeshRenderer->BaseColor));
|
||||
ImGui::Checkbox("Visible", &selectedObject->MeshRenderer->Visible);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MetaCoreId BoundObjectId_ = 0;
|
||||
std::array<char, 256> NameBuffer_{};
|
||||
};
|
||||
|
||||
class MetaCoreBuiltinEditorModule final : public MetaCoreIModule {
|
||||
public:
|
||||
std::string GetModuleName() const override { return "MetaCoreBuiltinEditorModule"; }
|
||||
|
||||
void Startup(MetaCoreEditorModuleRegistry& moduleRegistry) override {
|
||||
moduleRegistry.RegisterMenuProvider(std::make_unique<MetaCoreDefaultMenuProvider>());
|
||||
moduleRegistry.RegisterPanelProvider(std::make_unique<MetaCoreHierarchyPanelProvider>());
|
||||
moduleRegistry.RegisterPanelProvider(std::make_unique<MetaCoreScenePanelProvider>());
|
||||
moduleRegistry.RegisterPanelProvider(std::make_unique<MetaCoreInspectorPanelProvider>());
|
||||
moduleRegistry.RegisterPanelProvider(std::make_unique<MetaCoreProjectPanelProvider>());
|
||||
moduleRegistry.RegisterPanelProvider(std::make_unique<MetaCoreConsolePanelProvider>());
|
||||
moduleRegistry.RegisterInspectorDrawer(std::make_unique<MetaCoreTransformInspectorDrawer>());
|
||||
}
|
||||
|
||||
void Shutdown(MetaCoreEditorModuleRegistry&) override {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<MetaCoreIModule> MetaCoreCreateBuiltinEditorModule() {
|
||||
return std::make_unique<MetaCoreBuiltinEditorModule>();
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
12
Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.h
Normal file
12
Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreEditor/MetaCoreEditorModule.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 创建内置 Unity-like 编辑器模块。
|
||||
std::unique_ptr<MetaCoreIModule> MetaCoreCreateBuiltinEditorModule();
|
||||
|
||||
} // namespace MetaCore
|
||||
264
Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp
Normal file
264
Source/MetaCoreEditor/Private/MetaCoreEditorApp.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
#include "MetaCoreEditor/MetaCoreEditorApp.h"
|
||||
|
||||
#include "MetaCoreBuiltinEditorModule.h"
|
||||
#include "MetaCoreEditorCameraController.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
namespace {
|
||||
|
||||
void MetaCoreApplyEditorStyle() {
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImGui::StyleColorsDark();
|
||||
style.WindowRounding = 2.0F;
|
||||
style.FrameRounding = 2.0F;
|
||||
style.TabRounding = 2.0F;
|
||||
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_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);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.22F, 0.27F, 0.32F, 1.0F);
|
||||
style.Colors[ImGuiCol_Button] = ImVec4(0.18F, 0.21F, 0.25F, 1.0F);
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.23F, 0.28F, 0.33F, 1.0F);
|
||||
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);
|
||||
}
|
||||
|
||||
void MetaCoreConfigureChineseFont() {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->AddFontDefault();
|
||||
|
||||
#if defined(_WIN32)
|
||||
std::vector<std::filesystem::path> candidatePaths;
|
||||
char* windowsDirectory = nullptr;
|
||||
std::size_t windowsDirectoryLength = 0;
|
||||
if (_dupenv_s(&windowsDirectory, &windowsDirectoryLength, "WINDIR") == 0 && windowsDirectory != nullptr) {
|
||||
const std::filesystem::path fontsPath = std::filesystem::path(windowsDirectory) / "Fonts";
|
||||
candidatePaths.push_back(fontsPath / "msyh.ttc");
|
||||
candidatePaths.push_back(fontsPath / "msyhbd.ttc");
|
||||
candidatePaths.push_back(fontsPath / "simhei.ttf");
|
||||
free(windowsDirectory);
|
||||
}
|
||||
|
||||
for (const auto& candidatePath : candidatePaths) {
|
||||
if (std::filesystem::exists(candidatePath)) {
|
||||
ImFont* chineseFont = io.Fonts->AddFontFromFileTTF(
|
||||
candidatePath.string().c_str(),
|
||||
18.0F,
|
||||
nullptr,
|
||||
io.Fonts->GetGlyphRangesChineseFull()
|
||||
);
|
||||
if (chineseFont != nullptr) {
|
||||
io.FontDefault = chineseFont;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MetaCoreEditorApp::~MetaCoreEditorApp() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool MetaCoreEditorApp::Initialize() {
|
||||
if (Initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Window_.Initialize(1600, 900, "MetaCore Editor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RenderDevice_.Initialize(Window_.GetNativeHandle())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InitializeImGui()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ViewportRenderer_.Initialize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scene_ = MetaCoreCreateDefaultScene();
|
||||
Modules_.push_back(MetaCoreCreateBuiltinEditorModule());
|
||||
for (const auto& module : Modules_) {
|
||||
module->Startup(ModuleRegistry_);
|
||||
}
|
||||
|
||||
EditorContext_ = std::make_unique<MetaCoreEditorContext>(
|
||||
Window_,
|
||||
RenderDevice_,
|
||||
ViewportRenderer_,
|
||||
Scene_,
|
||||
LogService_,
|
||||
ModuleRegistry_
|
||||
);
|
||||
|
||||
for (const MetaCoreGameObject& object : Scene_.GetGameObjects()) {
|
||||
if (object.Name == "Cube") {
|
||||
EditorContext_->SetSelectedObjectId(object.Id);
|
||||
EditorContext_->GetCameraController().FocusGameObject(object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "System", "MetaCore 编辑器已初始化");
|
||||
EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Render", "OpenGL 场景视口已准备完成");
|
||||
|
||||
Initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int MetaCoreEditorApp::Run() {
|
||||
while (!Window_.ShouldClose()) {
|
||||
Window_.BeginFrame();
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_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));
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
Window_.EndFrame();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MetaCoreEditorApp::Shutdown() {
|
||||
if (!Initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& module : Modules_) {
|
||||
module->Shutdown(ModuleRegistry_);
|
||||
}
|
||||
Modules_.clear();
|
||||
EditorContext_.reset();
|
||||
ViewportRenderer_.Shutdown();
|
||||
ShutdownImGui();
|
||||
RenderDevice_.Shutdown();
|
||||
Window_.Shutdown();
|
||||
Initialized_ = false;
|
||||
}
|
||||
|
||||
bool MetaCoreEditorApp::InitializeImGui() {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
MetaCoreConfigureChineseFont();
|
||||
MetaCoreApplyEditorStyle();
|
||||
|
||||
if (!ImGui_ImplGlfw_InitForOpenGL(Window_.GetNativeHandle(), true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init("#version 330")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetaCoreEditorApp::ShutdownImGui() {
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
void MetaCoreEditorApp::DrawEditorFrame() {
|
||||
const ImGuiViewport* mainViewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(mainViewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(mainViewport->WorkSize);
|
||||
ImGui::SetNextWindowViewport(mainViewport->ID);
|
||||
|
||||
constexpr ImGuiWindowFlags hostWindowFlags =
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||
ImGuiWindowFlags_NoNavFocus |
|
||||
ImGuiWindowFlags_MenuBar;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0F);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0F, 0.0F));
|
||||
ImGui::Begin("MetaCoreMainDockSpace", nullptr, hostWindowFlags);
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
for (const auto& menuProvider : ModuleRegistry_.GetMenuProviders()) {
|
||||
menuProvider->DrawMenuBar(*EditorContext_);
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
const ImGuiID dockSpaceId = ImGui::GetID("MetaCoreDockSpaceId");
|
||||
ImGui::DockSpace(dockSpaceId, ImVec2(0.0F, 0.0F), ImGuiDockNodeFlags_PassthruCentralNode);
|
||||
EnsureDefaultDockLayout(dockSpaceId);
|
||||
ImGui::End();
|
||||
|
||||
for (const auto& panelProvider : ModuleRegistry_.GetPanelProviders()) {
|
||||
bool& panelOpen = ModuleRegistry_.AccessPanelOpenState(panelProvider->GetPanelId());
|
||||
if (!panelOpen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::Begin(panelProvider->GetPanelTitle().c_str(), &panelOpen);
|
||||
panelProvider->DrawPanel(*EditorContext_);
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void MetaCoreEditorApp::EnsureDefaultDockLayout(unsigned int dockSpaceId) {
|
||||
if (EditorContext_->HasDockLayoutBuilt()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::DockBuilderRemoveNode(dockSpaceId);
|
||||
ImGui::DockBuilderAddNode(dockSpaceId, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(dockSpaceId, ImGui::GetMainViewport()->Size);
|
||||
|
||||
ImGuiID mainNodeId = dockSpaceId;
|
||||
const ImGuiID leftNodeId = ImGui::DockBuilderSplitNode(mainNodeId, ImGuiDir_Left, 0.18F, nullptr, &mainNodeId);
|
||||
const ImGuiID rightNodeId = ImGui::DockBuilderSplitNode(mainNodeId, ImGuiDir_Right, 0.24F, nullptr, &mainNodeId);
|
||||
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);
|
||||
ImGui::DockBuilderFinish(dockSpaceId);
|
||||
|
||||
EditorContext_->SetDockLayoutBuilt(true);
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,83 @@
|
||||
#include "MetaCoreEditorCameraController.h"
|
||||
|
||||
#include "MetaCorePlatform/MetaCoreInput.h"
|
||||
#include "MetaCoreScene/MetaCoreGameObject.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
void MetaCoreEditorCameraController::Update(const MetaCoreSceneViewportState& viewportState, const MetaCoreInput& input) {
|
||||
if (!viewportState.Hovered && !viewportState.Focused) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
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);
|
||||
if (viewportState.Hovered && altDown && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
|
||||
YawDegrees_ += io.MouseDelta.x * 0.35F;
|
||||
PitchDegrees_ -= io.MouseDelta.y * 0.35F;
|
||||
PitchDegrees_ = std::clamp(PitchDegrees_, -85.0F, 85.0F);
|
||||
}
|
||||
|
||||
if (viewportState.Hovered && ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) {
|
||||
const glm::vec3 right = GetRightDirection();
|
||||
const glm::vec3 up = GetUpDirection();
|
||||
const float panScale = 0.01F * Distance_;
|
||||
Target_ -= right * io.MouseDelta.x * panScale;
|
||||
Target_ += up * io.MouseDelta.y * panScale;
|
||||
}
|
||||
}
|
||||
|
||||
void MetaCoreEditorCameraController::FocusGameObject(const MetaCoreGameObject& gameObject) {
|
||||
Target_ = gameObject.Transform.Position;
|
||||
const float scaleRadius = std::max({gameObject.Transform.Scale.x, gameObject.Transform.Scale.y, gameObject.Transform.Scale.z});
|
||||
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);
|
||||
}
|
||||
|
||||
glm::vec3 MetaCoreEditorCameraController::GetCameraPosition() const {
|
||||
return Target_ - GetForwardDirection() * Distance_;
|
||||
}
|
||||
|
||||
glm::vec3 MetaCoreEditorCameraController::GetForwardDirection() const {
|
||||
const float yawRadians = glm::radians(YawDegrees_);
|
||||
const float pitchRadians = glm::radians(PitchDegrees_);
|
||||
|
||||
glm::vec3 forward;
|
||||
forward.x = std::cos(pitchRadians) * std::sin(yawRadians);
|
||||
forward.y = std::sin(pitchRadians);
|
||||
forward.z = std::cos(pitchRadians) * std::cos(yawRadians);
|
||||
return glm::normalize(forward);
|
||||
}
|
||||
|
||||
glm::vec3 MetaCoreEditorCameraController::GetRightDirection() const {
|
||||
return glm::normalize(glm::cross(GetForwardDirection(), glm::vec3(0.0F, 1.0F, 0.0F)));
|
||||
}
|
||||
|
||||
glm::vec3 MetaCoreEditorCameraController::GetUpDirection() const {
|
||||
return glm::normalize(glm::cross(GetRightDirection(), GetForwardDirection()));
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreEditor/MetaCoreEditorContext.h"
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
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]] glm::vec3 GetCameraPosition() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] glm::vec3 GetForwardDirection() const;
|
||||
[[nodiscard]] glm::vec3 GetRightDirection() const;
|
||||
[[nodiscard]] glm::vec3 GetUpDirection() const;
|
||||
|
||||
glm::vec3 Target_{0.0F, 0.7F, 0.0F};
|
||||
float Distance_ = 7.5F;
|
||||
float YawDegrees_ = 38.0F;
|
||||
float PitchDegrees_ = -28.0F;
|
||||
float FieldOfViewDegrees_ = 60.0F;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
57
Source/MetaCoreEditor/Private/MetaCoreEditorContext.cpp
Normal file
57
Source/MetaCoreEditor/Private/MetaCoreEditorContext.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "MetaCoreEditor/MetaCoreEditorContext.h"
|
||||
|
||||
#include "MetaCoreEditorCameraController.h"
|
||||
#include "MetaCorePlatform/MetaCoreWindow.h"
|
||||
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
MetaCoreEditorContext::MetaCoreEditorContext(
|
||||
MetaCoreWindow& window,
|
||||
MetaCoreRenderDevice& renderDevice,
|
||||
MetaCoreEditorViewportRenderer& viewportRenderer,
|
||||
MetaCoreScene& scene,
|
||||
MetaCoreLogService& logService,
|
||||
MetaCoreEditorModuleRegistry& moduleRegistry
|
||||
)
|
||||
: Window_(window),
|
||||
RenderDevice_(renderDevice),
|
||||
ViewportRenderer_(viewportRenderer),
|
||||
Scene_(scene),
|
||||
LogService_(logService),
|
||||
ModuleRegistry_(moduleRegistry),
|
||||
CameraController_(std::make_unique<MetaCoreEditorCameraController>()) {
|
||||
}
|
||||
|
||||
MetaCoreEditorContext::~MetaCoreEditorContext() = default;
|
||||
|
||||
MetaCoreWindow& MetaCoreEditorContext::GetWindow() { return Window_; }
|
||||
MetaCoreInput& MetaCoreEditorContext::GetInput() { return Window_.GetInput(); }
|
||||
const MetaCoreInput& MetaCoreEditorContext::GetInput() const { return Window_.GetInput(); }
|
||||
MetaCoreRenderDevice& MetaCoreEditorContext::GetRenderDevice() { return RenderDevice_; }
|
||||
MetaCoreEditorViewportRenderer& MetaCoreEditorContext::GetViewportRenderer() { return ViewportRenderer_; }
|
||||
MetaCoreScene& MetaCoreEditorContext::GetScene() { return Scene_; }
|
||||
const MetaCoreScene& MetaCoreEditorContext::GetScene() const { return Scene_; }
|
||||
MetaCoreLogService& MetaCoreEditorContext::GetLogService() { return LogService_; }
|
||||
const MetaCoreLogService& MetaCoreEditorContext::GetLogService() const { return LogService_; }
|
||||
MetaCoreEditorModuleRegistry& MetaCoreEditorContext::GetModuleRegistry() { return ModuleRegistry_; }
|
||||
const MetaCoreEditorModuleRegistry& MetaCoreEditorContext::GetModuleRegistry() const { return ModuleRegistry_; }
|
||||
MetaCoreSceneViewportState& MetaCoreEditorContext::GetSceneViewportState() { return SceneViewportState_; }
|
||||
const MetaCoreSceneViewportState& MetaCoreEditorContext::GetSceneViewportState() const { return SceneViewportState_; }
|
||||
MetaCoreEditorCameraController& MetaCoreEditorContext::GetCameraController() { return *CameraController_; }
|
||||
const MetaCoreEditorCameraController& MetaCoreEditorContext::GetCameraController() const { return *CameraController_; }
|
||||
MetaCoreId MetaCoreEditorContext::GetSelectedObjectId() const { return SelectedObjectId_; }
|
||||
void MetaCoreEditorContext::SetSelectedObjectId(MetaCoreId objectId) { SelectedObjectId_ = objectId; }
|
||||
MetaCoreGameObject* MetaCoreEditorContext::GetSelectedGameObject() { return Scene_.FindGameObject(SelectedObjectId_); }
|
||||
const MetaCoreGameObject* MetaCoreEditorContext::GetSelectedGameObject() const { return Scene_.FindGameObject(SelectedObjectId_); }
|
||||
|
||||
void MetaCoreEditorContext::AddConsoleMessage(MetaCoreLogLevel level, const std::string& category, const std::string& message) {
|
||||
LogService_.AddEntry(level, category, message);
|
||||
}
|
||||
|
||||
void MetaCoreEditorContext::SetDockLayoutBuilt(bool built) { DockLayoutBuilt_ = built; }
|
||||
bool MetaCoreEditorContext::HasDockLayoutBuilt() const { return DockLayoutBuilt_; }
|
||||
|
||||
} // namespace MetaCore
|
||||
41
Source/MetaCoreEditor/Private/MetaCoreEditorModule.cpp
Normal file
41
Source/MetaCoreEditor/Private/MetaCoreEditorModule.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "MetaCoreEditor/MetaCoreEditorModule.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
void MetaCoreEditorModuleRegistry::RegisterMenuProvider(std::unique_ptr<MetaCoreIMenuProvider> provider) {
|
||||
MenuProviders_.push_back(std::move(provider));
|
||||
}
|
||||
|
||||
void MetaCoreEditorModuleRegistry::RegisterPanelProvider(std::unique_ptr<MetaCoreIEditorPanelProvider> provider) {
|
||||
PanelOpenStates_.emplace(provider->GetPanelId(), provider->IsOpenByDefault());
|
||||
PanelProviders_.push_back(std::move(provider));
|
||||
}
|
||||
|
||||
void MetaCoreEditorModuleRegistry::RegisterInspectorDrawer(std::unique_ptr<MetaCoreIInspectorDrawer> drawer) {
|
||||
InspectorDrawers_.push_back(std::move(drawer));
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<MetaCoreIMenuProvider>>& MetaCoreEditorModuleRegistry::GetMenuProviders() const {
|
||||
return MenuProviders_;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<MetaCoreIEditorPanelProvider>>& MetaCoreEditorModuleRegistry::GetPanelProviders() const {
|
||||
return PanelProviders_;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<MetaCoreIInspectorDrawer>>& MetaCoreEditorModuleRegistry::GetInspectorDrawers() const {
|
||||
return InspectorDrawers_;
|
||||
}
|
||||
|
||||
bool& MetaCoreEditorModuleRegistry::AccessPanelOpenState(const std::string& panelId) {
|
||||
return PanelOpenStates_[panelId];
|
||||
}
|
||||
|
||||
bool MetaCoreEditorModuleRegistry::IsPanelOpen(const std::string& panelId) const {
|
||||
const auto iterator = PanelOpenStates_.find(panelId);
|
||||
return iterator != PanelOpenStates_.end() ? iterator->second : false;
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreEditor/MetaCoreEditorContext.h"
|
||||
#include "MetaCoreEditor/MetaCoreEditorModule.h"
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreLogService.h"
|
||||
#include "MetaCorePlatform/MetaCoreWindow.h"
|
||||
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
class MetaCoreIModule;
|
||||
|
||||
// 负责组合窗口、渲染器、ImGui 和编辑器模块,形成完整的编辑器程序。
|
||||
class MetaCoreEditorApp {
|
||||
public:
|
||||
MetaCoreEditorApp() = default;
|
||||
~MetaCoreEditorApp();
|
||||
|
||||
bool Initialize();
|
||||
int Run();
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
bool InitializeImGui();
|
||||
void ShutdownImGui();
|
||||
void DrawEditorFrame();
|
||||
void EnsureDefaultDockLayout(unsigned int dockSpaceId);
|
||||
|
||||
MetaCoreWindow Window_{};
|
||||
MetaCoreRenderDevice RenderDevice_{};
|
||||
MetaCoreEditorViewportRenderer ViewportRenderer_{};
|
||||
MetaCoreScene Scene_{};
|
||||
MetaCoreLogService LogService_{};
|
||||
MetaCoreEditorModuleRegistry ModuleRegistry_{};
|
||||
std::vector<std::unique_ptr<MetaCoreIModule>> Modules_{};
|
||||
std::unique_ptr<MetaCoreEditorContext> EditorContext_{};
|
||||
bool Initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
#include "MetaCoreFoundation/MetaCoreLogService.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
class MetaCoreWindow;
|
||||
class MetaCoreInput;
|
||||
class MetaCoreRenderDevice;
|
||||
class MetaCoreEditorViewportRenderer;
|
||||
class MetaCoreScene;
|
||||
struct MetaCoreGameObject;
|
||||
class MetaCoreEditorModuleRegistry;
|
||||
class MetaCoreEditorCameraController;
|
||||
|
||||
// 描述场景视口当前的尺寸与焦点状态。
|
||||
struct MetaCoreSceneViewportState {
|
||||
float Width = 1.0F;
|
||||
float Height = 1.0F;
|
||||
bool Hovered = false;
|
||||
bool Focused = false;
|
||||
};
|
||||
|
||||
// 在编辑器各模块之间共享运行时状态。
|
||||
class MetaCoreEditorContext {
|
||||
public:
|
||||
MetaCoreEditorContext(
|
||||
MetaCoreWindow& window,
|
||||
MetaCoreRenderDevice& renderDevice,
|
||||
MetaCoreEditorViewportRenderer& viewportRenderer,
|
||||
MetaCoreScene& scene,
|
||||
MetaCoreLogService& logService,
|
||||
MetaCoreEditorModuleRegistry& moduleRegistry
|
||||
);
|
||||
~MetaCoreEditorContext();
|
||||
|
||||
[[nodiscard]] MetaCoreWindow& GetWindow();
|
||||
[[nodiscard]] MetaCoreInput& GetInput();
|
||||
[[nodiscard]] const MetaCoreInput& GetInput() const;
|
||||
[[nodiscard]] MetaCoreRenderDevice& GetRenderDevice();
|
||||
[[nodiscard]] MetaCoreEditorViewportRenderer& GetViewportRenderer();
|
||||
[[nodiscard]] MetaCoreScene& GetScene();
|
||||
[[nodiscard]] const MetaCoreScene& GetScene() const;
|
||||
[[nodiscard]] MetaCoreLogService& GetLogService();
|
||||
[[nodiscard]] const MetaCoreLogService& GetLogService() const;
|
||||
[[nodiscard]] MetaCoreEditorModuleRegistry& GetModuleRegistry();
|
||||
[[nodiscard]] const MetaCoreEditorModuleRegistry& GetModuleRegistry() const;
|
||||
[[nodiscard]] MetaCoreSceneViewportState& GetSceneViewportState();
|
||||
[[nodiscard]] const MetaCoreSceneViewportState& GetSceneViewportState() const;
|
||||
[[nodiscard]] MetaCoreEditorCameraController& GetCameraController();
|
||||
[[nodiscard]] const MetaCoreEditorCameraController& GetCameraController() const;
|
||||
[[nodiscard]] MetaCoreId GetSelectedObjectId() const;
|
||||
void SetSelectedObjectId(MetaCoreId objectId);
|
||||
[[nodiscard]] MetaCoreGameObject* GetSelectedGameObject();
|
||||
[[nodiscard]] const MetaCoreGameObject* GetSelectedGameObject() const;
|
||||
void AddConsoleMessage(MetaCoreLogLevel level, const std::string& category, const std::string& message);
|
||||
void SetDockLayoutBuilt(bool built);
|
||||
[[nodiscard]] bool HasDockLayoutBuilt() const;
|
||||
|
||||
private:
|
||||
MetaCoreWindow& Window_;
|
||||
MetaCoreRenderDevice& RenderDevice_;
|
||||
MetaCoreEditorViewportRenderer& ViewportRenderer_;
|
||||
MetaCoreScene& Scene_;
|
||||
MetaCoreLogService& LogService_;
|
||||
MetaCoreEditorModuleRegistry& ModuleRegistry_;
|
||||
std::unique_ptr<MetaCoreEditorCameraController> CameraController_;
|
||||
MetaCoreSceneViewportState SceneViewportState_{};
|
||||
MetaCoreId SelectedObjectId_ = 0;
|
||||
bool DockLayoutBuilt_ = false;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
class MetaCoreEditorContext;
|
||||
struct MetaCoreGameObject;
|
||||
|
||||
// 定义可向编辑器注册菜单的扩展接口。
|
||||
class MetaCoreIMenuProvider {
|
||||
public:
|
||||
virtual ~MetaCoreIMenuProvider() = default;
|
||||
[[nodiscard]] virtual std::string GetProviderId() const = 0;
|
||||
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;
|
||||
virtual void DrawPanel(MetaCoreEditorContext& editorContext) = 0;
|
||||
};
|
||||
|
||||
// 定义可向 Inspector 注册组件绘制器的扩展接口。
|
||||
class MetaCoreIInspectorDrawer {
|
||||
public:
|
||||
virtual ~MetaCoreIInspectorDrawer() = default;
|
||||
[[nodiscard]] virtual std::string GetDrawerId() const = 0;
|
||||
[[nodiscard]] virtual bool Supports(const MetaCoreGameObject& gameObject) const = 0;
|
||||
virtual void DrawInspector(MetaCoreEditorContext& editorContext, MetaCoreGameObject& gameObject) = 0;
|
||||
};
|
||||
|
||||
// 管理编辑器中全部可扩展菜单、面板和 Inspector 绘制器。
|
||||
class MetaCoreEditorModuleRegistry {
|
||||
public:
|
||||
void RegisterMenuProvider(std::unique_ptr<MetaCoreIMenuProvider> provider);
|
||||
void RegisterPanelProvider(std::unique_ptr<MetaCoreIEditorPanelProvider> provider);
|
||||
void RegisterInspectorDrawer(std::unique_ptr<MetaCoreIInspectorDrawer> drawer);
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<MetaCoreIMenuProvider>>& GetMenuProviders() const;
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<MetaCoreIEditorPanelProvider>>& GetPanelProviders() const;
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<MetaCoreIInspectorDrawer>>& GetInspectorDrawers() const;
|
||||
|
||||
bool& AccessPanelOpenState(const std::string& panelId);
|
||||
[[nodiscard]] bool IsPanelOpen(const std::string& panelId) const;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<MetaCoreIMenuProvider>> MenuProviders_{};
|
||||
std::vector<std::unique_ptr<MetaCoreIEditorPanelProvider>> PanelProviders_{};
|
||||
std::vector<std::unique_ptr<MetaCoreIInspectorDrawer>> InspectorDrawers_{};
|
||||
std::unordered_map<std::string, bool> PanelOpenStates_{};
|
||||
};
|
||||
|
||||
// 定义一个可注册到编辑器中的模块生命周期接口。
|
||||
class MetaCoreIModule {
|
||||
public:
|
||||
virtual ~MetaCoreIModule() = default;
|
||||
[[nodiscard]] virtual std::string GetModuleName() const = 0;
|
||||
virtual void Startup(MetaCoreEditorModuleRegistry& moduleRegistry) = 0;
|
||||
virtual void Shutdown(MetaCoreEditorModuleRegistry& moduleRegistry) = 0;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
17
Source/MetaCoreFoundation/Private/MetaCoreId.cpp
Normal file
17
Source/MetaCoreFoundation/Private/MetaCoreId.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
namespace {
|
||||
|
||||
std::atomic<std::uint64_t> GMetaCoreNextId{1};
|
||||
|
||||
} // namespace
|
||||
|
||||
MetaCoreId MetaCoreIdGenerator::Generate() {
|
||||
return GMetaCoreNextId.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
23
Source/MetaCoreFoundation/Private/MetaCoreLogService.cpp
Normal file
23
Source/MetaCoreFoundation/Private/MetaCoreLogService.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "MetaCoreFoundation/MetaCoreLogService.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
void MetaCoreLogService::AddEntry(MetaCoreLogLevel level, std::string category, std::string message) {
|
||||
Entries_.push_back(MetaCoreLogEntry{
|
||||
level,
|
||||
std::move(category),
|
||||
std::move(message)
|
||||
});
|
||||
}
|
||||
|
||||
const std::vector<MetaCoreLogEntry>& MetaCoreLogService::GetEntries() const {
|
||||
return Entries_;
|
||||
}
|
||||
|
||||
void MetaCoreLogService::Clear() {
|
||||
Entries_.clear();
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// MetaCore 全局对象标识类型。
|
||||
using MetaCoreId = std::uint64_t;
|
||||
|
||||
// 负责为场景对象和运行时实体分配递增标识。
|
||||
class MetaCoreIdGenerator {
|
||||
public:
|
||||
// 生成一个新的全局唯一标识。
|
||||
static MetaCoreId Generate();
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 定义 MetaCore 控制台消息的级别。
|
||||
enum class MetaCoreLogLevel {
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
// 表示一条会显示在编辑器控制台中的日志记录。
|
||||
struct MetaCoreLogEntry {
|
||||
MetaCoreLogLevel Level = MetaCoreLogLevel::Info;
|
||||
std::string Category;
|
||||
std::string Message;
|
||||
};
|
||||
|
||||
// 提供最基础的日志收集能力,供编辑器控制台和调试输出复用。
|
||||
class MetaCoreLogService {
|
||||
public:
|
||||
// 写入一条新的日志。
|
||||
void AddEntry(MetaCoreLogLevel level, std::string category, std::string message);
|
||||
|
||||
// 返回当前收集到的全部日志。
|
||||
[[nodiscard]] const std::vector<MetaCoreLogEntry>& GetEntries() const;
|
||||
|
||||
// 清空全部日志记录。
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
std::vector<MetaCoreLogEntry> Entries_;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
59
Source/MetaCorePlatform/Private/MetaCoreInput.cpp
Normal file
59
Source/MetaCorePlatform/Private/MetaCoreInput.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "MetaCorePlatform/MetaCoreInput.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
void MetaCoreInput::BeginFrame(GLFWwindow* nativeWindow) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool MetaCoreInput::IsKeyDown(int key) const {
|
||||
if (key < 0 || key >= static_cast<int>(CurrentKeyStates_.size())) {
|
||||
return false;
|
||||
}
|
||||
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::IsMouseButtonDown(int button) const {
|
||||
if (button < 0 || button >= static_cast<int>(CurrentMouseStates_.size())) {
|
||||
return false;
|
||||
}
|
||||
return CurrentMouseStates_[static_cast<std::size_t>(button)];
|
||||
}
|
||||
|
||||
const glm::vec2& MetaCoreInput::GetCursorPosition() const {
|
||||
return CursorPosition_;
|
||||
}
|
||||
|
||||
const glm::vec2& MetaCoreInput::GetCursorDelta() const {
|
||||
return CursorDelta_;
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
99
Source/MetaCorePlatform/Private/MetaCoreWindow.cpp
Normal file
99
Source/MetaCorePlatform/Private/MetaCoreWindow.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "MetaCorePlatform/MetaCoreWindow.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
MetaCoreWindow::~MetaCoreWindow() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool MetaCoreWindow::Initialize(int width, int height, const std::string& title) {
|
||||
if (NativeHandle_ != nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (glfwInit() != GLFW_TRUE) {
|
||||
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();
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(NativeHandle_);
|
||||
glfwSwapInterval(1);
|
||||
LastFrameTime_ = glfwGetTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetaCoreWindow::Shutdown() {
|
||||
if (NativeHandle_ != nullptr) {
|
||||
glfwDestroyWindow(NativeHandle_);
|
||||
NativeHandle_ = nullptr;
|
||||
glfwTerminate();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Input_.BeginFrame(NativeHandle_);
|
||||
}
|
||||
|
||||
void MetaCoreWindow::EndFrame() const {
|
||||
glfwSwapBuffers(NativeHandle_);
|
||||
}
|
||||
|
||||
bool MetaCoreWindow::ShouldClose() const {
|
||||
return NativeHandle_ == nullptr || glfwWindowShouldClose(NativeHandle_) == GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWwindow* MetaCoreWindow::GetNativeHandle() const {
|
||||
return NativeHandle_;
|
||||
}
|
||||
|
||||
MetaCoreInput& MetaCoreWindow::GetInput() {
|
||||
return Input_;
|
||||
}
|
||||
|
||||
const MetaCoreInput& MetaCoreWindow::GetInput() const {
|
||||
return Input_;
|
||||
}
|
||||
|
||||
float MetaCoreWindow::GetDeltaSeconds() const {
|
||||
return DeltaSeconds_;
|
||||
}
|
||||
|
||||
std::pair<int, int> MetaCoreWindow::GetWindowSize() const {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
glfwGetWindowSize(NativeHandle_, &width, &height);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
std::pair<int, int> MetaCoreWindow::GetFramebufferSize() const {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
glfwGetFramebufferSize(NativeHandle_, &width, &height);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 统一封装窗口轮询后的键鼠状态,避免上层直接依赖 GLFW 轮询细节。
|
||||
class MetaCoreInput {
|
||||
public:
|
||||
// 由窗口层在每帧轮询事件后刷新一次输入状态。
|
||||
void BeginFrame(GLFWwindow* nativeWindow);
|
||||
|
||||
// 判断按键当前是否处于按下状态。
|
||||
[[nodiscard]] bool IsKeyDown(int key) const;
|
||||
|
||||
// 判断按键是否在本帧刚刚按下。
|
||||
[[nodiscard]] bool WasKeyPressed(int key) const;
|
||||
|
||||
// 判断鼠标按键当前是否按下。
|
||||
[[nodiscard]] bool IsMouseButtonDown(int button) 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_{};
|
||||
glm::vec2 CursorPosition_{0.0F, 0.0F};
|
||||
glm::vec2 CursorDelta_{0.0F, 0.0F};
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCorePlatform/MetaCoreInput.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 负责管理主窗口、时间步进和最基础的事件轮询。
|
||||
class MetaCoreWindow {
|
||||
public:
|
||||
MetaCoreWindow() = default;
|
||||
~MetaCoreWindow();
|
||||
|
||||
// 创建主窗口并初始化 OpenGL 上下文。
|
||||
bool Initialize(int width, int height, const std::string& title);
|
||||
|
||||
// 释放窗口及 GLFW 资源。
|
||||
void Shutdown();
|
||||
|
||||
// 轮询事件并刷新输入状态。
|
||||
void BeginFrame();
|
||||
|
||||
// 交换前后缓冲区。
|
||||
void EndFrame() const;
|
||||
|
||||
// 返回窗口是否请求关闭。
|
||||
[[nodiscard]] bool ShouldClose() const;
|
||||
|
||||
// 返回原生 GLFW 窗口指针。
|
||||
[[nodiscard]] GLFWwindow* GetNativeHandle() 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;
|
||||
|
||||
private:
|
||||
GLFWwindow* NativeHandle_ = nullptr;
|
||||
MetaCoreInput Input_{};
|
||||
float DeltaSeconds_ = 1.0F / 60.0F;
|
||||
double LastFrameTime_ = 0.0;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
110
Source/MetaCoreRender/Private/MetaCoreDebugGeometry.cpp
Normal file
110
Source/MetaCoreRender/Private/MetaCoreDebugGeometry.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#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
|
||||
116
Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp
Normal file
116
Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
|
||||
|
||||
#include "MetaCoreRender/MetaCoreSceneRenderer.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
bool MetaCoreEditorViewportRenderer::Initialize() {
|
||||
Shutdown();
|
||||
|
||||
SceneRenderer_ = new MetaCoreSceneRenderer();
|
||||
if (!SceneRenderer_->Initialize()) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
RebuildFramebuffer();
|
||||
return FramebufferHandle_ != 0;
|
||||
}
|
||||
|
||||
void MetaCoreEditorViewportRenderer::Shutdown() {
|
||||
DestroyFramebuffer();
|
||||
|
||||
if (SceneRenderer_ != nullptr) {
|
||||
SceneRenderer_->Shutdown();
|
||||
delete SceneRenderer_;
|
||||
SceneRenderer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MetaCoreEditorViewportRenderer::Resize(int width, int height) {
|
||||
width = (width > 1) ? width : 1;
|
||||
height = (height > 1) ? height : 1;
|
||||
|
||||
if (width == Width_ && height == Height_) {
|
||||
return;
|
||||
}
|
||||
|
||||
Width_ = width;
|
||||
Height_ = height;
|
||||
RebuildFramebuffer();
|
||||
}
|
||||
|
||||
void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView) {
|
||||
if (FramebufferHandle_ == 0 || SceneRenderer_ == 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;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
82
Source/MetaCoreRender/Private/MetaCoreMesh.cpp
Normal file
82
Source/MetaCoreRender/Private/MetaCoreMesh.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#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
|
||||
45
Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp
Normal file
45
Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
bool MetaCoreRenderDevice::Initialize(GLFWwindow* nativeWindow) {
|
||||
if (Initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CCW);
|
||||
glDisable(GL_BLEND);
|
||||
Initialized_ = nativeWindow != nullptr;
|
||||
return Initialized_;
|
||||
}
|
||||
|
||||
void MetaCoreRenderDevice::Shutdown() {
|
||||
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::Clear(const glm::vec4& clearColor) const {
|
||||
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
bool MetaCoreRenderDevice::IsInitialized() const {
|
||||
return Initialized_;
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
209
Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp
Normal file
209
Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
#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
|
||||
110
Source/MetaCoreRender/Private/MetaCoreShaderProgram.cpp
Normal file
110
Source/MetaCoreRender/Private/MetaCoreShaderProgram.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#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
|
||||
@ -0,0 +1,31 @@
|
||||
#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
|
||||
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
class MetaCoreScene;
|
||||
|
||||
// 管理编辑器场景视口所需的离屏帧缓冲。
|
||||
class MetaCoreEditorViewportRenderer {
|
||||
public:
|
||||
// 初始化离屏渲染器和场景渲染器。
|
||||
bool Initialize();
|
||||
|
||||
// 释放离屏缓冲与场景渲染器资源。
|
||||
void Shutdown();
|
||||
|
||||
// 根据新的视口尺寸重建帧缓冲。
|
||||
void Resize(int width, int height);
|
||||
|
||||
// 将场景渲染到当前离屏纹理中。
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
47
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreMesh.h
Normal file
47
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreMesh.h
Normal file
@ -0,0 +1,47 @@
|
||||
#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,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec4.hpp>
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 负责初始化 glad,并管理当前 OpenGL 上下文的基础状态。
|
||||
class MetaCoreRenderDevice {
|
||||
public:
|
||||
// 初始化 OpenGL 函数加载与默认渲染状态。
|
||||
bool Initialize(GLFWwindow* nativeWindow);
|
||||
|
||||
// 关闭设备并重置初始化状态。
|
||||
void Shutdown();
|
||||
|
||||
// 开始绘制默认帧缓冲。
|
||||
void BeginFrame(int width, int height, const glm::vec4& clearColor) const;
|
||||
|
||||
// 清理默认帧缓冲。
|
||||
void Clear(const glm::vec4& clearColor) const;
|
||||
|
||||
// 返回设备是否已初始化。
|
||||
[[nodiscard]] bool IsInitialized() const;
|
||||
|
||||
private:
|
||||
bool Initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 描述一次场景渲染所需的视图参数。
|
||||
struct MetaCoreSceneView {
|
||||
glm::mat4 ViewMatrix{1.0F};
|
||||
glm::mat4 ProjectionMatrix{1.0F};
|
||||
glm::vec3 CameraPosition{0.0F, 0.0F, 0.0F};
|
||||
MetaCoreId SelectedObjectId = 0;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,26 @@
|
||||
#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
|
||||
@ -0,0 +1,41 @@
|
||||
#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
|
||||
86
Source/MetaCoreScene/Private/MetaCoreScene.cpp
Normal file
86
Source/MetaCoreScene/Private/MetaCoreScene.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
MetaCoreGameObject& MetaCoreScene::CreateGameObject(const std::string& name, MetaCoreId parentId) {
|
||||
GameObjects_.push_back(MetaCoreGameObject{
|
||||
MetaCoreIdGenerator::Generate(),
|
||||
parentId,
|
||||
name,
|
||||
MetaCoreTransformComponent{},
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
std::nullopt
|
||||
});
|
||||
return GameObjects_.back();
|
||||
}
|
||||
|
||||
MetaCoreGameObject* MetaCoreScene::FindGameObject(MetaCoreId objectId) {
|
||||
for (MetaCoreGameObject& object : GameObjects_) {
|
||||
if (object.Id == objectId) {
|
||||
return &object;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const MetaCoreGameObject* MetaCoreScene::FindGameObject(MetaCoreId objectId) const {
|
||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
||||
if (object.Id == objectId) {
|
||||
return &object;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<MetaCoreGameObject>& MetaCoreScene::GetGameObjects() {
|
||||
return GameObjects_;
|
||||
}
|
||||
|
||||
const std::vector<MetaCoreGameObject>& MetaCoreScene::GetGameObjects() const {
|
||||
return GameObjects_;
|
||||
}
|
||||
|
||||
std::vector<MetaCoreId> MetaCoreScene::GetRootObjectIds() const {
|
||||
std::vector<MetaCoreId> rootIds;
|
||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
||||
if (object.ParentId == 0) {
|
||||
rootIds.push_back(object.Id);
|
||||
}
|
||||
}
|
||||
return rootIds;
|
||||
}
|
||||
|
||||
std::vector<MetaCoreId> MetaCoreScene::GetChildrenOf(MetaCoreId parentId) const {
|
||||
std::vector<MetaCoreId> childIds;
|
||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
||||
if (object.ParentId == parentId) {
|
||||
childIds.push_back(object.Id);
|
||||
}
|
||||
}
|
||||
return childIds;
|
||||
}
|
||||
|
||||
MetaCoreScene MetaCoreCreateDefaultScene() {
|
||||
MetaCoreScene scene;
|
||||
|
||||
MetaCoreGameObject& mainCamera = scene.CreateGameObject("Main Camera");
|
||||
mainCamera.Camera = MetaCoreCameraComponent{};
|
||||
mainCamera.Camera->IsPrimary = true;
|
||||
mainCamera.Transform.Position = glm::vec3(0.0F, 2.2F, 6.5F);
|
||||
mainCamera.Transform.RotationEulerDegrees = glm::vec3(-15.0F, 0.0F, 0.0F);
|
||||
|
||||
MetaCoreGameObject& directionalLight = scene.CreateGameObject("Directional Light");
|
||||
directionalLight.Light = MetaCoreLightComponent{};
|
||||
directionalLight.Transform.RotationEulerDegrees = glm::vec3(-45.0F, 30.0F, 0.0F);
|
||||
|
||||
MetaCoreGameObject& cube = scene.CreateGameObject("Cube");
|
||||
cube.MeshRenderer = MetaCoreMeshRendererComponent{};
|
||||
cube.Transform.Position = glm::vec3(0.0F, 0.5F, 0.0F);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 定义第一阶段内置的网格类型。
|
||||
enum class MetaCoreBuiltinMeshType {
|
||||
Cube
|
||||
};
|
||||
|
||||
// 表示 Unity 风格对象的变换组件。
|
||||
struct MetaCoreTransformComponent {
|
||||
glm::vec3 Position{0.0F, 0.0F, 0.0F};
|
||||
glm::vec3 RotationEulerDegrees{0.0F, 0.0F, 0.0F};
|
||||
glm::vec3 Scale{1.0F, 1.0F, 1.0F};
|
||||
};
|
||||
|
||||
// 表示场景中用于观察的摄像机组件。
|
||||
struct MetaCoreCameraComponent {
|
||||
float FieldOfViewDegrees = 60.0F;
|
||||
float NearClip = 0.1F;
|
||||
float FarClip = 100.0F;
|
||||
bool IsPrimary = false;
|
||||
};
|
||||
|
||||
// 表示一个最小可用的网格渲染组件。
|
||||
struct MetaCoreMeshRendererComponent {
|
||||
MetaCoreBuiltinMeshType BuiltinMesh = MetaCoreBuiltinMeshType::Cube;
|
||||
glm::vec3 BaseColor{0.75F, 0.78F, 0.84F};
|
||||
bool Visible = true;
|
||||
};
|
||||
|
||||
// 表示第一阶段场景中的方向光组件。
|
||||
struct MetaCoreLightComponent {
|
||||
glm::vec3 Color{1.0F, 1.0F, 1.0F};
|
||||
float Intensity = 1.5F;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
#include "MetaCoreScene/MetaCoreComponents.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 表示一个 Unity 风格的场景对象。
|
||||
struct MetaCoreGameObject {
|
||||
MetaCoreId Id = 0;
|
||||
MetaCoreId ParentId = 0;
|
||||
std::string Name;
|
||||
MetaCoreTransformComponent Transform{};
|
||||
std::optional<MetaCoreCameraComponent> Camera;
|
||||
std::optional<MetaCoreMeshRendererComponent> MeshRenderer;
|
||||
std::optional<MetaCoreLightComponent> Light;
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
36
Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreScene.h
Normal file
36
Source/MetaCoreScene/Public/MetaCoreScene/MetaCoreScene.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreScene/MetaCoreGameObject.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
// 负责存储和查询场景中的全部对象。
|
||||
class MetaCoreScene {
|
||||
public:
|
||||
// 创建一个新的场景对象。
|
||||
MetaCoreGameObject& CreateGameObject(const std::string& name, MetaCoreId parentId = 0);
|
||||
|
||||
// 通过标识查找场景对象。
|
||||
[[nodiscard]] MetaCoreGameObject* FindGameObject(MetaCoreId objectId);
|
||||
[[nodiscard]] const MetaCoreGameObject* FindGameObject(MetaCoreId objectId) const;
|
||||
|
||||
// 返回全部对象。
|
||||
[[nodiscard]] std::vector<MetaCoreGameObject>& GetGameObjects();
|
||||
[[nodiscard]] const std::vector<MetaCoreGameObject>& GetGameObjects() const;
|
||||
|
||||
// 返回根节点对象列表。
|
||||
[[nodiscard]] std::vector<MetaCoreId> GetRootObjectIds() const;
|
||||
|
||||
// 返回某个对象的直接子对象列表。
|
||||
[[nodiscard]] std::vector<MetaCoreId> GetChildrenOf(MetaCoreId parentId) const;
|
||||
|
||||
private:
|
||||
std::vector<MetaCoreGameObject> GameObjects_{};
|
||||
};
|
||||
|
||||
// 创建一个包含默认相机、灯光和立方体的启动场景。
|
||||
MetaCoreScene MetaCoreCreateDefaultScene();
|
||||
|
||||
} // namespace MetaCore
|
||||
54
tests/MetaCoreSmokeTests.cpp
Normal file
54
tests/MetaCoreSmokeTests.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "MetaCoreEditor/MetaCoreEditorModule.h"
|
||||
#include "MetaCoreFoundation/MetaCoreLogService.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
|
||||
void MetaCoreExpect(bool condition, const char* message) {
|
||||
if (!condition) {
|
||||
std::cerr << "MetaCoreSmokeTests failed: " << message << '\n';
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
class MetaCoreDummyPanelProvider final : public MetaCore::MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Dummy"; }
|
||||
std::string GetPanelTitle() const override { return "Dummy"; }
|
||||
bool IsOpenByDefault() const override { return false; }
|
||||
void DrawPanel(MetaCore::MetaCoreEditorContext&) override {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
MetaCore::MetaCoreScene scene = MetaCore::MetaCoreCreateDefaultScene();
|
||||
MetaCoreExpect(scene.GetGameObjects().size() == 3, "默认场景应包含三个对象");
|
||||
|
||||
bool hasCamera = false;
|
||||
bool hasLight = false;
|
||||
bool hasCube = false;
|
||||
for (const MetaCore::MetaCoreGameObject& object : scene.GetGameObjects()) {
|
||||
hasCamera = hasCamera || object.Camera.has_value();
|
||||
hasLight = hasLight || object.Light.has_value();
|
||||
hasCube = hasCube || object.MeshRenderer.has_value();
|
||||
}
|
||||
|
||||
MetaCoreExpect(hasCamera, "默认场景应包含摄像机");
|
||||
MetaCoreExpect(hasLight, "默认场景应包含光源");
|
||||
MetaCoreExpect(hasCube, "默认场景应包含立方体");
|
||||
|
||||
MetaCore::MetaCoreEditorModuleRegistry moduleRegistry;
|
||||
moduleRegistry.RegisterPanelProvider(std::make_unique<MetaCoreDummyPanelProvider>());
|
||||
MetaCoreExpect(!moduleRegistry.AccessPanelOpenState("Dummy"), "面板默认状态应为关闭");
|
||||
|
||||
MetaCore::MetaCoreLogService logService;
|
||||
logService.AddEntry(MetaCore::MetaCoreLogLevel::Info, "Test", "Smoke");
|
||||
MetaCoreExpect(logService.GetEntries().size() == 1, "日志服务应记录一条日志");
|
||||
|
||||
std::cout << "MetaCoreSmokeTests passed\n";
|
||||
return 0;
|
||||
}
|
||||
23
vcpkg.json
Normal file
23
vcpkg.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"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",
|
||||
"opengl3-binding"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user