refactor: 迁移GameObject到EnTT ECS架构并修复编译错误
This commit is contained in:
parent
3b1aa895aa
commit
c8021a9206
@ -193,6 +193,7 @@ add_library(MetaCoreScene STATIC
|
|||||||
target_include_directories(MetaCoreScene
|
target_include_directories(MetaCoreScene
|
||||||
PUBLIC
|
PUBLIC
|
||||||
Source/MetaCoreScene/Public
|
Source/MetaCoreScene/Public
|
||||||
|
third_party
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(MetaCoreScene
|
target_link_libraries(MetaCoreScene
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -295,17 +295,17 @@ void MetaCoreDrawSelectionBoundsOverlay(
|
|||||||
ImVec2 groupMax(-FLT_MAX, -FLT_MAX);
|
ImVec2 groupMax(-FLT_MAX, -FLT_MAX);
|
||||||
|
|
||||||
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
||||||
const MetaCoreGameObject* selectedObject = scene.FindGameObject(selectedObjectId);
|
const MetaCoreGameObject selectedObject = scene.FindGameObject(selectedObjectId);
|
||||||
if (selectedObject == nullptr) {
|
if (!selectedObject) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::vec3 halfExtents(
|
const glm::vec3 halfExtents(
|
||||||
std::max(std::abs(selectedObject->Transform.Scale.x), 0.5F) * 0.5F,
|
std::max(std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.x), 0.5F) * 0.5F,
|
||||||
std::max(std::abs(selectedObject->Transform.Scale.y), 0.5F) * 0.5F,
|
std::max(std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.y), 0.5F) * 0.5F,
|
||||||
std::max(std::abs(selectedObject->Transform.Scale.z), 0.5F) * 0.5F
|
std::max(std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.z), 0.5F) * 0.5F
|
||||||
);
|
);
|
||||||
const glm::vec3 center = selectedObject->Transform.Position;
|
const glm::vec3 center = selectedObject.GetComponent<MetaCoreTransformComponent>().Position;
|
||||||
|
|
||||||
const std::array<glm::vec3, 8> corners = {
|
const std::array<glm::vec3, 8> corners = {
|
||||||
center + glm::vec3(-halfExtents.x, -halfExtents.y, -halfExtents.z),
|
center + glm::vec3(-halfExtents.x, -halfExtents.y, -halfExtents.z),
|
||||||
@ -347,7 +347,7 @@ void MetaCoreDrawSelectionBoundsOverlay(
|
|||||||
const ImU32 strokeColor = isActive ? activeBoxColor : boxColor;
|
const ImU32 strokeColor = isActive ? activeBoxColor : boxColor;
|
||||||
drawList->AddRectFilled(minPoint, maxPoint, fillColor, 2.0F);
|
drawList->AddRectFilled(minPoint, maxPoint, fillColor, 2.0F);
|
||||||
drawList->AddRect(minPoint, maxPoint, strokeColor, 2.0F, 0, isActive ? 2.0F : 1.5F);
|
drawList->AddRect(minPoint, maxPoint, strokeColor, 2.0F, 0, isActive ? 2.0F : 1.5F);
|
||||||
drawList->AddText(ImVec2(minPoint.x, minPoint.y - 18.0F), strokeColor, selectedObject->Name.c_str());
|
drawList->AddText(ImVec2(minPoint.x, minPoint.y - 18.0F), strokeColor, selectedObject.GetName().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedObjectIds.size() > 1 && hasGroupBounds) {
|
if (selectedObjectIds.size() > 1 && hasGroupBounds) {
|
||||||
@ -360,6 +360,73 @@ void MetaCoreDrawSelectionBoundsOverlay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MetaCoreDrawCompatibilityScenePreviewOverlay(
|
||||||
|
const MetaCoreScene& scene,
|
||||||
|
const MetaCoreSceneView& sceneView,
|
||||||
|
const MetaCoreSceneViewportState& viewportState
|
||||||
|
) {
|
||||||
|
if (viewportState.Width <= 1.0F || viewportState.Height <= 1.0F) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImDrawList* drawList = ImGui::GetForegroundDrawList();
|
||||||
|
for (const MetaCoreGameObject& gameObject : scene.GetGameObjects()) {
|
||||||
|
if (!gameObject.HasComponent<MetaCoreMeshRendererComponent>() || !gameObject.GetComponent<MetaCoreMeshRendererComponent>().Visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::vec3 halfExtents(
|
||||||
|
std::max(std::abs(gameObject.GetComponent<MetaCoreTransformComponent>().Scale.x), 0.5F) * 0.5F,
|
||||||
|
std::max(std::abs(gameObject.GetComponent<MetaCoreTransformComponent>().Scale.y), 0.5F) * 0.5F,
|
||||||
|
std::max(std::abs(gameObject.GetComponent<MetaCoreTransformComponent>().Scale.z), 0.5F) * 0.5F
|
||||||
|
);
|
||||||
|
const glm::vec3 center = gameObject.GetComponent<MetaCoreTransformComponent>().Position;
|
||||||
|
const std::array<glm::vec3, 8> corners = {
|
||||||
|
center + glm::vec3(-halfExtents.x, -halfExtents.y, -halfExtents.z),
|
||||||
|
center + glm::vec3( halfExtents.x, -halfExtents.y, -halfExtents.z),
|
||||||
|
center + glm::vec3(-halfExtents.x, halfExtents.y, -halfExtents.z),
|
||||||
|
center + glm::vec3( halfExtents.x, halfExtents.y, -halfExtents.z),
|
||||||
|
center + glm::vec3(-halfExtents.x, -halfExtents.y, halfExtents.z),
|
||||||
|
center + glm::vec3( halfExtents.x, -halfExtents.y, halfExtents.z),
|
||||||
|
center + glm::vec3(-halfExtents.x, halfExtents.y, halfExtents.z),
|
||||||
|
center + glm::vec3( halfExtents.x, halfExtents.y, halfExtents.z)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool anyPointVisible = false;
|
||||||
|
ImVec2 minPoint(FLT_MAX, FLT_MAX);
|
||||||
|
ImVec2 maxPoint(-FLT_MAX, -FLT_MAX);
|
||||||
|
for (const glm::vec3& corner : corners) {
|
||||||
|
ImVec2 screenPoint{};
|
||||||
|
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, corner, screenPoint)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
anyPointVisible = true;
|
||||||
|
minPoint.x = std::min(minPoint.x, screenPoint.x);
|
||||||
|
minPoint.y = std::min(minPoint.y, screenPoint.y);
|
||||||
|
maxPoint.x = std::max(maxPoint.x, screenPoint.x);
|
||||||
|
maxPoint.y = std::max(maxPoint.y, screenPoint.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyPointVisible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto toByte = [](float value) -> int {
|
||||||
|
return static_cast<int>(std::clamp(value, 0.0F, 1.0F) * 255.0F);
|
||||||
|
};
|
||||||
|
const ImU32 fillColor = IM_COL32(
|
||||||
|
toByte(gameObject.GetComponent<MetaCoreMeshRendererComponent>().BaseColor.r),
|
||||||
|
toByte(gameObject.GetComponent<MetaCoreMeshRendererComponent>().BaseColor.g),
|
||||||
|
toByte(gameObject.GetComponent<MetaCoreMeshRendererComponent>().BaseColor.b),
|
||||||
|
105
|
||||||
|
);
|
||||||
|
const ImU32 strokeColor = IM_COL32(210, 226, 245, 190);
|
||||||
|
drawList->AddRectFilled(minPoint, maxPoint, fillColor, 2.0F);
|
||||||
|
drawList->AddRect(minPoint, maxPoint, strokeColor, 2.0F, 0, 1.2F);
|
||||||
|
drawList->AddText(ImVec2(minPoint.x + 4.0F, minPoint.y + 4.0F), strokeColor, gameObject.GetName().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MetaCoreDrawSelectionHierarchyOverlay(
|
void MetaCoreDrawSelectionHierarchyOverlay(
|
||||||
const MetaCoreEditorContext& editorContext,
|
const MetaCoreEditorContext& editorContext,
|
||||||
const MetaCoreScene& scene,
|
const MetaCoreScene& scene,
|
||||||
@ -376,20 +443,20 @@ void MetaCoreDrawSelectionHierarchyOverlay(
|
|||||||
const ImU32 lineColor = IM_COL32(255, 230, 160, 140);
|
const ImU32 lineColor = IM_COL32(255, 230, 160, 140);
|
||||||
|
|
||||||
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
||||||
const MetaCoreGameObject* childObject = scene.FindGameObject(selectedObjectId);
|
const MetaCoreGameObject childObject = scene.FindGameObject(selectedObjectId);
|
||||||
if (childObject == nullptr || childObject->ParentId == 0 || !selectedSet.contains(childObject->ParentId)) {
|
if (!childObject || childObject.GetParentId() == 0 || !selectedSet.contains(childObject.GetParentId())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaCoreGameObject* parentObject = scene.FindGameObject(childObject->ParentId);
|
const MetaCoreGameObject parentObject = scene.FindGameObject(childObject.GetParentId());
|
||||||
if (parentObject == nullptr) {
|
if (!parentObject) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImVec2 childPoint{};
|
ImVec2 childPoint{};
|
||||||
ImVec2 parentPoint{};
|
ImVec2 parentPoint{};
|
||||||
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, childObject->Transform.Position, childPoint) ||
|
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, childObject.GetComponent<MetaCoreTransformComponent>().Position, childPoint) ||
|
||||||
!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, parentObject->Transform.Position, parentPoint)) {
|
!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, parentObject.GetComponent<MetaCoreTransformComponent>().Position, parentPoint)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,11 +480,11 @@ void MetaCoreDrawSelectionGroupCenterOverlay(
|
|||||||
glm::vec3 center(0.0F);
|
glm::vec3 center(0.0F);
|
||||||
int validObjectCount = 0;
|
int validObjectCount = 0;
|
||||||
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
||||||
const MetaCoreGameObject* selectedObject = scene.FindGameObject(selectedObjectId);
|
const MetaCoreGameObject selectedObject = scene.FindGameObject(selectedObjectId);
|
||||||
if (selectedObject == nullptr) {
|
if (!selectedObject) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
center += selectedObject->Transform.Position;
|
center += selectedObject.GetComponent<MetaCoreTransformComponent>().Position;
|
||||||
++validObjectCount;
|
++validObjectCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,8 +711,8 @@ bool MetaCoreEditorApp::Initialize() {
|
|||||||
MetaCoreTraceStartup("metacore.app: select default focus object");
|
MetaCoreTraceStartup("metacore.app: select default focus object");
|
||||||
if (EditorContext_->GetSelectedObjectId() == 0) {
|
if (EditorContext_->GetSelectedObjectId() == 0) {
|
||||||
for (const MetaCoreGameObject& object : Scene_.GetGameObjects()) {
|
for (const MetaCoreGameObject& object : Scene_.GetGameObjects()) {
|
||||||
if (object.Name == "Cube" || object.Name == "Demo Cube") {
|
if (object.GetName() == "Cube" || object.GetName() == "Demo Cube") {
|
||||||
EditorContext_->SetSelectedObjectId(object.Id);
|
EditorContext_->SetSelectedObjectId(object.GetId());
|
||||||
EditorContext_->GetCameraController().FocusGameObject(object);
|
EditorContext_->GetCameraController().FocusGameObject(object);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -667,12 +734,12 @@ bool MetaCoreEditorApp::Initialize() {
|
|||||||
EditorContext_->AddConsoleMessage(
|
EditorContext_->AddConsoleMessage(
|
||||||
MetaCoreLogLevel::Warning,
|
MetaCoreLogLevel::Warning,
|
||||||
"Render",
|
"Render",
|
||||||
"Debug 兼容模式已启用:MetaCore 场景对象同步已临时禁用,窗口可稳定运行,但 3D 场景内容不会完整显示"
|
"Debug 兼容模式已启用:当前优先保证 MetaCore 编辑器稳定运行,部分 3D 场景内容会暂时简化显示"
|
||||||
);
|
);
|
||||||
EditorContext_->AddConsoleMessage(
|
EditorContext_->AddConsoleMessage(
|
||||||
MetaCoreLogLevel::Info,
|
MetaCoreLogLevel::Info,
|
||||||
"Render",
|
"Render",
|
||||||
"如需调试底层场景同步,可设置环境变量 METACORE_ENABLE_DEBUG_SCENE_SYNC=1 后重启编辑器"
|
"如需继续排查场景同步问题,可设置开发环境变量 METACORE_ENABLE_DEBUG_SCENE_SYNC=1 后重启编辑器"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (loadedStartupScene) {
|
if (loadedStartupScene) {
|
||||||
@ -726,10 +793,10 @@ void MetaCoreEditorApp::Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreEditorApp::InitializeImGui() {
|
bool MetaCoreEditorApp::InitializeImGui() {
|
||||||
MetaCoreTraceStartup("metacore.ui: imgui begin");
|
MetaCoreTraceStartup("metacore.ui: initialize begin");
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
MetaCoreTraceStartup("metacore.ui: imgui context created");
|
MetaCoreTraceStartup("metacore.ui: context created");
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
@ -738,23 +805,23 @@ bool MetaCoreEditorApp::InitializeImGui() {
|
|||||||
io.IniFilename = nullptr;
|
io.IniFilename = nullptr;
|
||||||
io.LogFilename = nullptr;
|
io.LogFilename = nullptr;
|
||||||
#endif
|
#endif
|
||||||
MetaCoreTraceStartup("metacore.ui: configure font begin");
|
MetaCoreTraceStartup("metacore.ui: font setup begin");
|
||||||
MetaCoreConfigureChineseFont();
|
MetaCoreConfigureChineseFont();
|
||||||
MetaCoreTraceStartup("metacore.ui: configure font done");
|
MetaCoreTraceStartup("metacore.ui: font setup done");
|
||||||
MetaCoreApplyEditorStyle();
|
MetaCoreApplyEditorStyle();
|
||||||
MetaCoreTraceStartup("metacore.ui: style done");
|
MetaCoreTraceStartup("metacore.ui: editor style ready");
|
||||||
|
|
||||||
if (!ImGui_ImplWin32_InitForOpenGL(Window_.GetNativeWindowHandle())) {
|
if (!ImGui_ImplWin32_InitForOpenGL(Window_.GetNativeWindowHandle())) {
|
||||||
MetaCoreTraceStartup("metacore.ui: win32 init failed");
|
MetaCoreTraceStartup("metacore.ui: platform backend init failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MetaCoreTraceStartup("metacore.ui: win32 init done");
|
MetaCoreTraceStartup("metacore.ui: platform backend ready");
|
||||||
|
|
||||||
if (!ImGui_ImplOpenGL3_Init("#version 130")) {
|
if (!ImGui_ImplOpenGL3_Init("#version 130")) {
|
||||||
MetaCoreTraceStartup("metacore.ui: opengl3 init failed");
|
MetaCoreTraceStartup("metacore.ui: graphics backend init failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MetaCoreTraceStartup("metacore.ui: opengl3 init done");
|
MetaCoreTraceStartup("metacore.ui: graphics backend ready");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -857,7 +924,7 @@ void MetaCoreEditorApp::DrawEditorFrame() {
|
|||||||
if (ModuleRegistry_.IsPanelOpen("Scene")) {
|
if (ModuleRegistry_.IsPanelOpen("Scene")) {
|
||||||
ImGuiDockNode* centralNode = ImGui::DockBuilderGetCentralNode(dockSpaceId);
|
ImGuiDockNode* centralNode = ImGui::DockBuilderGetCentralNode(dockSpaceId);
|
||||||
if (centralNode != nullptr) {
|
if (centralNode != nullptr) {
|
||||||
// Viewport Tabs (Scene / Game)
|
// MetaCore main viewport keeps a Unity-like Scene / Game mental model.
|
||||||
ImGui::SetNextWindowPos(centralNode->Pos);
|
ImGui::SetNextWindowPos(centralNode->Pos);
|
||||||
ImGui::SetNextWindowSize(ImVec2(centralNode->Size.x, 30.0F));
|
ImGui::SetNextWindowSize(ImVec2(centralNode->Size.x, 30.0F));
|
||||||
ImGui::Begin("ViewportTabs", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
ImGui::Begin("ViewportTabs", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||||
@ -894,7 +961,7 @@ void MetaCoreEditorApp::DrawEditorFrame() {
|
|||||||
viewportState.Focused = viewportState.Hovered && !ImGui::GetIO().WantCaptureMouse;
|
viewportState.Focused = viewportState.Hovered && !ImGui::GetIO().WantCaptureMouse;
|
||||||
|
|
||||||
if (viewportState.Focused && !ImGui::GetIO().WantCaptureKeyboard && EditorContext_->GetInput().WasKeyPressed(MetaCoreInputKey::Focus)) {
|
if (viewportState.Focused && !ImGui::GetIO().WantCaptureKeyboard && EditorContext_->GetInput().WasKeyPressed(MetaCoreInputKey::Focus)) {
|
||||||
if (MetaCoreGameObject* selectedObject = EditorContext_->GetSelectedGameObject(); selectedObject != nullptr) {
|
if (MetaCoreGameObject selectedObject = EditorContext_->GetSelectedGameObject(); selectedObject) {
|
||||||
EditorContext_->GetCameraController().FocusGameObject(*selectedObject);
|
EditorContext_->GetCameraController().FocusGameObject(*selectedObject);
|
||||||
EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Scene", "相机已聚焦到当前对象");
|
EditorContext_->AddConsoleMessage(MetaCoreLogLevel::Info, "Scene", "相机已聚焦到当前对象");
|
||||||
}
|
}
|
||||||
@ -991,6 +1058,9 @@ void MetaCoreEditorApp::DrawEditorFrame() {
|
|||||||
|
|
||||||
|
|
||||||
MetaCoreDrawViewportGridOverlay(*EditorContext_, viewportState);
|
MetaCoreDrawViewportGridOverlay(*EditorContext_, viewportState);
|
||||||
|
if (ViewportRenderer_.IsSceneSyncDegraded()) {
|
||||||
|
MetaCoreDrawCompatibilityScenePreviewOverlay(Scene_, sceneView, viewportState);
|
||||||
|
}
|
||||||
MetaCoreDrawWorldOriginOverlay(*EditorContext_, sceneView, viewportState);
|
MetaCoreDrawWorldOriginOverlay(*EditorContext_, sceneView, viewportState);
|
||||||
MetaCoreDrawSelectionBoundsOverlay(*EditorContext_, Scene_, sceneView, viewportState);
|
MetaCoreDrawSelectionBoundsOverlay(*EditorContext_, Scene_, sceneView, viewportState);
|
||||||
MetaCoreDrawSelectionGroupCenterOverlay(*EditorContext_, Scene_, sceneView, viewportState);
|
MetaCoreDrawSelectionGroupCenterOverlay(*EditorContext_, Scene_, sceneView, viewportState);
|
||||||
@ -1021,12 +1091,12 @@ void MetaCoreEditorApp::DrawEditorFrame() {
|
|||||||
overlayDrawList->AddText(
|
overlayDrawList->AddText(
|
||||||
ImVec2(overlayMin.x + 12.0F, overlayMin.y + 28.0F),
|
ImVec2(overlayMin.x + 12.0F, overlayMin.y + 28.0F),
|
||||||
IM_COL32(240, 226, 208, 255),
|
IM_COL32(240, 226, 208, 255),
|
||||||
"已暂时关闭 MetaCore 场景对象同步,避免视口导致编辑器崩溃"
|
"当前优先保证 MetaCore 编辑器稳定运行,3D 视图会先显示可渲染对象"
|
||||||
);
|
);
|
||||||
overlayDrawList->AddText(
|
overlayDrawList->AddText(
|
||||||
ImVec2(overlayMin.x + 12.0F, overlayMin.y + 44.0F),
|
ImVec2(overlayMin.x + 12.0F, overlayMin.y + 44.0F),
|
||||||
IM_COL32(209, 199, 184, 255),
|
IM_COL32(209, 199, 184, 255),
|
||||||
"可设置 METACORE_ENABLE_DEBUG_SCENE_SYNC=1 进行强制测试"
|
"Camera/Light 等非渲染节点暂时简化,可设置 METACORE_ENABLE_DEBUG_SCENE_SYNC=1 继续开发测试"
|
||||||
);
|
);
|
||||||
if (!ViewportRenderer_.GetLastSceneSyncFailure().empty()) {
|
if (!ViewportRenderer_.GetLastSceneSyncFailure().empty()) {
|
||||||
overlayDrawList->AddText(
|
overlayDrawList->AddText(
|
||||||
|
|||||||
@ -86,35 +86,35 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lhs.Camera.has_value() != rhs.Camera.has_value()) {
|
if (lhs.HasComponent<MetaCoreCameraComponent>() != rhs.HasComponent<MetaCoreCameraComponent>()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (lhs.Camera.has_value()) {
|
if (lhs.HasComponent<MetaCoreCameraComponent>()) {
|
||||||
if (!MetaCoreNearlyEqual(lhs.Camera->FieldOfViewDegrees, rhs.Camera->FieldOfViewDegrees) ||
|
if (!MetaCoreNearlyEqual(lhs.GetComponent<MetaCoreCameraComponent>().FieldOfViewDegrees, rhs.GetComponent<MetaCoreCameraComponent>().FieldOfViewDegrees) ||
|
||||||
!MetaCoreNearlyEqual(lhs.Camera->NearClip, rhs.Camera->NearClip) ||
|
!MetaCoreNearlyEqual(lhs.GetComponent<MetaCoreCameraComponent>().NearClip, rhs.GetComponent<MetaCoreCameraComponent>().NearClip) ||
|
||||||
!MetaCoreNearlyEqual(lhs.Camera->FarClip, rhs.Camera->FarClip) ||
|
!MetaCoreNearlyEqual(lhs.GetComponent<MetaCoreCameraComponent>().FarClip, rhs.GetComponent<MetaCoreCameraComponent>().FarClip) ||
|
||||||
lhs.Camera->IsPrimary != rhs.Camera->IsPrimary) {
|
lhs.GetComponent<MetaCoreCameraComponent>().IsPrimary != rhs.GetComponent<MetaCoreCameraComponent>().IsPrimary) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lhs.MeshRenderer.has_value() != rhs.MeshRenderer.has_value()) {
|
if (lhs.HasComponent<MetaCoreMeshRendererComponent>() != rhs.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (lhs.MeshRenderer.has_value()) {
|
if (lhs.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||||||
if (lhs.MeshRenderer->BuiltinMesh != rhs.MeshRenderer->BuiltinMesh ||
|
if (lhs.GetComponent<MetaCoreMeshRendererComponent>().BuiltinMesh != rhs.GetComponent<MetaCoreMeshRendererComponent>().BuiltinMesh ||
|
||||||
!MetaCoreNearlyEqualVec3(lhs.MeshRenderer->BaseColor, rhs.MeshRenderer->BaseColor) ||
|
!MetaCoreNearlyEqualVec3(lhs.GetComponent<MetaCoreMeshRendererComponent>().BaseColor, rhs.GetComponent<MetaCoreMeshRendererComponent>().BaseColor) ||
|
||||||
lhs.MeshRenderer->Visible != rhs.MeshRenderer->Visible) {
|
lhs.GetComponent<MetaCoreMeshRendererComponent>().Visible != rhs.GetComponent<MetaCoreMeshRendererComponent>().Visible) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lhs.Light.has_value() != rhs.Light.has_value()) {
|
if (lhs.HasComponent<MetaCoreLightComponent>() != rhs.HasComponent<MetaCoreLightComponent>()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (lhs.Light.has_value()) {
|
if (lhs.HasComponent<MetaCoreLightComponent>()) {
|
||||||
if (!MetaCoreNearlyEqualVec3(lhs.Light->Color, rhs.Light->Color) ||
|
if (!MetaCoreNearlyEqualVec3(lhs.GetComponent<MetaCoreLightComponent>().Color, rhs.GetComponent<MetaCoreLightComponent>().Color) ||
|
||||||
!MetaCoreNearlyEqual(lhs.Light->Intensity, rhs.Light->Intensity)) {
|
!MetaCoreNearlyEqual(lhs.GetComponent<MetaCoreLightComponent>().Intensity, rhs.GetComponent<MetaCoreLightComponent>().Intensity)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,8 +330,8 @@ void MetaCoreEditorContext::SelectRangeByOrderedIds(const std::vector<MetaCoreId
|
|||||||
|
|
||||||
MetaCoreId MetaCoreEditorContext::GetSelectedObjectId() const { return ActiveObjectId_; }
|
MetaCoreId MetaCoreEditorContext::GetSelectedObjectId() const { return ActiveObjectId_; }
|
||||||
void MetaCoreEditorContext::SetSelectedObjectId(MetaCoreId objectId) { SelectOnly(objectId); }
|
void MetaCoreEditorContext::SetSelectedObjectId(MetaCoreId objectId) { SelectOnly(objectId); }
|
||||||
MetaCoreGameObject* MetaCoreEditorContext::GetSelectedGameObject() { return Scene_.FindGameObject(ActiveObjectId_); }
|
MetaCoreGameObject MetaCoreEditorContext::GetSelectedGameObject() { return Scene_.FindGameObject(ActiveObjectId_); }
|
||||||
const MetaCoreGameObject* MetaCoreEditorContext::GetSelectedGameObject() const { return Scene_.FindGameObject(ActiveObjectId_); }
|
const MetaCoreGameObject MetaCoreEditorContext::GetSelectedGameObject() const { return Scene_.FindGameObject(ActiveObjectId_); }
|
||||||
MetaCoreGizmoOperation MetaCoreEditorContext::GetGizmoOperation() const { return GizmoOperation_; }
|
MetaCoreGizmoOperation MetaCoreEditorContext::GetGizmoOperation() const { return GizmoOperation_; }
|
||||||
void MetaCoreEditorContext::SetGizmoOperation(MetaCoreGizmoOperation operation) { GizmoOperation_ = operation; }
|
void MetaCoreEditorContext::SetGizmoOperation(MetaCoreGizmoOperation operation) { GizmoOperation_ = operation; }
|
||||||
MetaCoreGizmoMode MetaCoreEditorContext::GetGizmoMode() const { return GizmoMode_; }
|
MetaCoreGizmoMode MetaCoreEditorContext::GetGizmoMode() const { return GizmoMode_; }
|
||||||
|
|||||||
@ -39,21 +39,21 @@ glm::mat4 MetaCoreBuildTransformMatrix(const MetaCoreTransformComponent& transfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 MetaCoreBuildWorldTransformMatrix(const MetaCoreScene& scene, MetaCoreId objectId) {
|
glm::mat4 MetaCoreBuildWorldTransformMatrix(const MetaCoreScene& scene, MetaCoreId objectId) {
|
||||||
const MetaCoreGameObject* object = scene.FindGameObject(objectId);
|
const MetaCoreGameObject object = scene.FindGameObject(objectId);
|
||||||
if (object == nullptr) {
|
if (!object) {
|
||||||
return glm::mat4(1.0F);
|
return glm::mat4(1.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 worldMatrix = MetaCoreBuildTransformMatrix(object->Transform);
|
glm::mat4 worldMatrix = MetaCoreBuildTransformMatrix(object.GetComponent<MetaCoreTransformComponent>());
|
||||||
MetaCoreId parentId = object->ParentId;
|
MetaCoreId parentId = object.GetParentId();
|
||||||
while (parentId != 0) {
|
while (parentId != 0) {
|
||||||
const MetaCoreGameObject* parentObject = scene.FindGameObject(parentId);
|
const MetaCoreGameObject parentObject = scene.FindGameObject(parentId);
|
||||||
if (parentObject == nullptr) {
|
if (!parentObject) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
worldMatrix = MetaCoreBuildTransformMatrix(parentObject->Transform) * worldMatrix;
|
worldMatrix = MetaCoreBuildTransformMatrix(parentObject.GetComponent<MetaCoreTransformComponent>()) * worldMatrix;
|
||||||
parentId = parentObject->ParentId;
|
parentId = parentObject.GetParentId();
|
||||||
}
|
}
|
||||||
|
|
||||||
return worldMatrix;
|
return worldMatrix;
|
||||||
@ -170,14 +170,14 @@ MetaCoreId MetaCoreSceneInteractionService::PickGameObjectFromViewport(
|
|||||||
return cacheIterator->second;
|
return cacheIterator->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaCoreGameObject* object = scene.FindGameObject(objectId);
|
const MetaCoreGameObject object = scene.FindGameObject(objectId);
|
||||||
if (object == nullptr) {
|
if (!object) {
|
||||||
return glm::mat4(1.0F);
|
return glm::mat4(1.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 worldMatrix = MetaCoreBuildTransformMatrix(object->Transform);
|
glm::mat4 worldMatrix = MetaCoreBuildTransformMatrix(object.GetComponent<MetaCoreTransformComponent>());
|
||||||
if (object->ParentId != 0) {
|
if (object.GetParentId() != 0) {
|
||||||
worldMatrix = self(self, object->ParentId) * worldMatrix;
|
worldMatrix = self(self, object.GetParentId()) * worldMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
worldMatrixCache.emplace(objectId, worldMatrix);
|
worldMatrixCache.emplace(objectId, worldMatrix);
|
||||||
@ -188,11 +188,11 @@ MetaCoreId MetaCoreSceneInteractionService::PickGameObjectFromViewport(
|
|||||||
float bestHitDistance = std::numeric_limits<float>::max();
|
float bestHitDistance = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
for (const MetaCoreGameObject& gameObject : scene.GetGameObjects()) {
|
for (const MetaCoreGameObject& gameObject : scene.GetGameObjects()) {
|
||||||
if (!gameObject.MeshRenderer.has_value() || !gameObject.MeshRenderer->Visible) {
|
if (!gameObject.HasComponent<MetaCoreMeshRendererComponent>() || !gameObject.GetComponent<MetaCoreMeshRendererComponent>().Visible) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::mat4 worldMatrix = buildWorldMatrix(buildWorldMatrix, gameObject.Id);
|
const glm::mat4 worldMatrix = buildWorldMatrix(buildWorldMatrix, gameObject.GetId());
|
||||||
const glm::mat4 inverseWorldMatrix = glm::inverse(worldMatrix);
|
const glm::mat4 inverseWorldMatrix = glm::inverse(worldMatrix);
|
||||||
const glm::vec3 localRayOrigin = glm::vec3(inverseWorldMatrix * glm::vec4(rayOrigin, 1.0F));
|
const glm::vec3 localRayOrigin = glm::vec3(inverseWorldMatrix * glm::vec4(rayOrigin, 1.0F));
|
||||||
const glm::vec3 localRayDirection = glm::normalize(glm::vec3(inverseWorldMatrix * glm::vec4(rayDirection, 0.0F)));
|
const glm::vec3 localRayDirection = glm::normalize(glm::vec3(inverseWorldMatrix * glm::vec4(rayDirection, 0.0F)));
|
||||||
@ -234,7 +234,7 @@ MetaCoreId MetaCoreSceneInteractionService::PickGameObjectFromViewport(
|
|||||||
const float hitDistance = nearDistance >= 0.0F ? nearDistance : farDistance;
|
const float hitDistance = nearDistance >= 0.0F ? nearDistance : farDistance;
|
||||||
if (hitDistance >= 0.0F && hitDistance < bestHitDistance) {
|
if (hitDistance >= 0.0F && hitDistance < bestHitDistance) {
|
||||||
bestHitDistance = hitDistance;
|
bestHitDistance = hitDistance;
|
||||||
bestObjectId = gameObject.Id;
|
bestObjectId = gameObject.GetId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,8 +285,8 @@ void MetaCoreSceneInteractionService::FocusSelectedObject(MetaCoreEditorContext&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (selectedObjectIds.size() == 1) {
|
if (selectedObjectIds.size() == 1) {
|
||||||
MetaCoreGameObject* selectedObject = editorContext.GetSelectedGameObject();
|
MetaCoreGameObject selectedObject = editorContext.GetSelectedGameObject();
|
||||||
if (selectedObject != nullptr) {
|
if (selectedObject) {
|
||||||
editorContext.GetCameraController().FocusGameObject(*selectedObject);
|
editorContext.GetCameraController().FocusGameObject(*selectedObject);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -296,19 +296,19 @@ void MetaCoreSceneInteractionService::FocusSelectedObject(MetaCoreEditorContext&
|
|||||||
glm::vec3 boundsMin(0.0F);
|
glm::vec3 boundsMin(0.0F);
|
||||||
glm::vec3 boundsMax(0.0F);
|
glm::vec3 boundsMax(0.0F);
|
||||||
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
|
||||||
const MetaCoreGameObject* selectedObject = editorContext.GetScene().FindGameObject(selectedObjectId);
|
const MetaCoreGameObject selectedObject = editorContext.GetScene().FindGameObject(selectedObjectId);
|
||||||
if (selectedObject == nullptr) {
|
if (!selectedObject) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float extent = std::max({
|
const float extent = std::max({
|
||||||
std::abs(selectedObject->Transform.Scale.x),
|
std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.x),
|
||||||
std::abs(selectedObject->Transform.Scale.y),
|
std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.y),
|
||||||
std::abs(selectedObject->Transform.Scale.z),
|
std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.z),
|
||||||
0.5F
|
0.5F
|
||||||
});
|
});
|
||||||
const glm::vec3 objectMin = selectedObject->Transform.Position - glm::vec3(extent);
|
const glm::vec3 objectMin = selectedObject.GetComponent<MetaCoreTransformComponent>().Position - glm::vec3(extent);
|
||||||
const glm::vec3 objectMax = selectedObject->Transform.Position + glm::vec3(extent);
|
const glm::vec3 objectMax = selectedObject.GetComponent<MetaCoreTransformComponent>().Position + glm::vec3(extent);
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
boundsMin = objectMin;
|
boundsMin = objectMin;
|
||||||
@ -338,18 +338,18 @@ void MetaCoreSceneInteractionService::FocusVisibleScene(MetaCoreEditorContext& e
|
|||||||
glm::vec3 boundsMax(0.0F);
|
glm::vec3 boundsMax(0.0F);
|
||||||
|
|
||||||
for (const MetaCoreGameObject& gameObject : gameObjects) {
|
for (const MetaCoreGameObject& gameObject : gameObjects) {
|
||||||
if (gameObject.MeshRenderer.has_value() && !gameObject.MeshRenderer->Visible) {
|
if (gameObject.HasComponent<MetaCoreMeshRendererComponent>() && !gameObject.GetComponent<MetaCoreMeshRendererComponent>().Visible) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float extent = std::max({
|
const float extent = std::max({
|
||||||
std::abs(gameObject.Transform.Scale.x),
|
std::abs(gameObject.GetComponent<MetaCoreTransformComponent>().Scale.x),
|
||||||
std::abs(gameObject.Transform.Scale.y),
|
std::abs(gameObject.GetComponent<MetaCoreTransformComponent>().Scale.y),
|
||||||
std::abs(gameObject.Transform.Scale.z),
|
std::abs(gameObject.GetComponent<MetaCoreTransformComponent>().Scale.z),
|
||||||
0.5F
|
0.5F
|
||||||
});
|
});
|
||||||
const glm::vec3 objectMin = gameObject.Transform.Position - glm::vec3(extent);
|
const glm::vec3 objectMin = gameObject.GetComponent<MetaCoreTransformComponent>().Position - glm::vec3(extent);
|
||||||
const glm::vec3 objectMax = gameObject.Transform.Position + glm::vec3(extent);
|
const glm::vec3 objectMax = gameObject.GetComponent<MetaCoreTransformComponent>().Position + glm::vec3(extent);
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
boundsMin = objectMin;
|
boundsMin = objectMin;
|
||||||
@ -378,8 +378,8 @@ void MetaCoreSceneInteractionService::HandleGizmoManipulation(MetaCoreEditorCont
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCoreGameObject* selectedObject = editorContext.GetSelectedGameObject();
|
MetaCoreGameObject selectedObject = editorContext.GetSelectedGameObject();
|
||||||
if (selectedObject == nullptr) {
|
if (!selectedObject) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +392,7 @@ void MetaCoreSceneInteractionService::HandleGizmoManipulation(MetaCoreEditorCont
|
|||||||
gizmoAspect, 0.05F, 500.0F
|
gizmoAspect, 0.05F, 500.0F
|
||||||
);
|
);
|
||||||
|
|
||||||
glm::mat4 worldMatrixMetaCore = MetaCoreBuildWorldTransformMatrix(editorContext.GetScene(), selectedObject->Id);
|
glm::mat4 worldMatrixMetaCore = MetaCoreBuildWorldTransformMatrix(editorContext.GetScene(), selectedObject.GetId());
|
||||||
const glm::mat4 originalWorldMatrixMetaCore = worldMatrixMetaCore;
|
const glm::mat4 originalWorldMatrixMetaCore = worldMatrixMetaCore;
|
||||||
|
|
||||||
ImGuizmo::SetOrthographic(false);
|
ImGuizmo::SetOrthographic(false);
|
||||||
@ -429,12 +429,12 @@ void MetaCoreSceneInteractionService::HandleGizmoManipulation(MetaCoreEditorCont
|
|||||||
|
|
||||||
if (gizmoUsing && gizmoMatrix != originalWorldMatrixMetaCore) {
|
if (gizmoUsing && gizmoMatrix != originalWorldMatrixMetaCore) {
|
||||||
glm::mat4 newLocalMatrix = gizmoMatrix;
|
glm::mat4 newLocalMatrix = gizmoMatrix;
|
||||||
if (selectedObject->ParentId != 0) {
|
if (selectedObject.GetParentId() != 0) {
|
||||||
const glm::mat4 parentWorldMatrixMetaCore = MetaCoreBuildWorldTransformMatrix(editorContext.GetScene(), selectedObject->ParentId);
|
const glm::mat4 parentWorldMatrixMetaCore = MetaCoreBuildWorldTransformMatrix(editorContext.GetScene(), selectedObject.GetParentId());
|
||||||
newLocalMatrix = glm::inverse(parentWorldMatrixMetaCore) * gizmoMatrix;
|
newLocalMatrix = glm::inverse(parentWorldMatrixMetaCore) * gizmoMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCoreApplyMatrixToTransform(newLocalMatrix, selectedObject->Transform);
|
MetaCoreApplyMatrixToTransform(newLocalMatrix, selectedObject.GetComponent<MetaCoreTransformComponent>());
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleGizmoBeginUse(editorContext, gizmoUsing);
|
HandleGizmoBeginUse(editorContext, gizmoUsing);
|
||||||
@ -545,13 +545,13 @@ void MetaCoreSceneInteractionService::DrawViewportToolbar(MetaCoreEditorContext&
|
|||||||
if (selectedObjectIds.empty()) {
|
if (selectedObjectIds.empty()) {
|
||||||
ImGui::TextDisabled("Selection: None");
|
ImGui::TextDisabled("Selection: None");
|
||||||
} else if (selectedObjectIds.size() == 1) {
|
} else if (selectedObjectIds.size() == 1) {
|
||||||
const MetaCoreGameObject* activeObject = editorContext.GetSelectedGameObject();
|
const MetaCoreGameObject activeObject = editorContext.GetSelectedGameObject();
|
||||||
ImGui::TextDisabled(
|
ImGui::TextDisabled(
|
||||||
"Selection: %s",
|
"Selection: %s",
|
||||||
activeObject != nullptr ? activeObject->Name.c_str() : "<Missing>"
|
activeObject != nullptr ? activeObject->Name.c_str() : "<Missing>"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const MetaCoreGameObject* activeObject = editorContext.GetSelectedGameObject();
|
const MetaCoreGameObject activeObject = editorContext.GetSelectedGameObject();
|
||||||
ImGui::TextDisabled(
|
ImGui::TextDisabled(
|
||||||
"Selection: %zu objects | Active: %s",
|
"Selection: %zu objects | Active: %s",
|
||||||
selectedObjectIds.size(),
|
selectedObjectIds.size(),
|
||||||
|
|||||||
@ -17,7 +17,6 @@ namespace MetaCore {
|
|||||||
|
|
||||||
class MetaCoreIModule;
|
class MetaCoreIModule;
|
||||||
|
|
||||||
// 负责组合窗口、渲染器、ImGui 和编辑器模块,形成完整的编辑器程序。
|
|
||||||
class MetaCoreEditorApp {
|
class MetaCoreEditorApp {
|
||||||
public:
|
public:
|
||||||
MetaCoreEditorApp() = default;
|
MetaCoreEditorApp() = default;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "MetaCoreFoundation/MetaCoreAssetGuid.h"
|
#include "MetaCoreFoundation/MetaCoreAssetGuid.h"
|
||||||
|
#include "MetaCoreFoundation/MetaCoreAssetTypes.h"
|
||||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||||
#include "MetaCoreFoundation/MetaCorePackage.h"
|
#include "MetaCoreFoundation/MetaCorePackage.h"
|
||||||
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
||||||
@ -154,6 +155,45 @@ public:
|
|||||||
[[nodiscard]] virtual bool ReimportAsset(const MetaCoreAssetGuid& assetGuid) = 0;
|
[[nodiscard]] virtual bool ReimportAsset(const MetaCoreAssetGuid& assetGuid) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MetaCoreResolvedGeneratedAssetRecord {
|
||||||
|
MetaCoreAssetRecord SourceAsset{};
|
||||||
|
std::string GeneratedKind{};
|
||||||
|
std::size_t GeneratedIndex = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MetaCoreIAssetEditingService : public MetaCoreIEditorService {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] virtual std::optional<MetaCoreModelAssetDocument> LoadModelAsset(
|
||||||
|
const MetaCoreAssetGuid& assetGuid
|
||||||
|
) const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::optional<MetaCoreMeshAssetDocument> LoadMeshAsset(
|
||||||
|
const MetaCoreAssetGuid& meshGuid
|
||||||
|
) const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::optional<MetaCoreMaterialAssetDocument> LoadMaterialAsset(
|
||||||
|
const MetaCoreAssetGuid& materialGuid
|
||||||
|
) const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::optional<MetaCoreTextureAssetDocument> LoadTextureAsset(
|
||||||
|
const MetaCoreAssetGuid& textureGuid
|
||||||
|
) const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool SaveModelImportSettings(
|
||||||
|
const MetaCoreAssetGuid& modelGuid,
|
||||||
|
const MetaCoreModelImportSettingsDocument& importSettings
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool SaveMaterialAsset(
|
||||||
|
const MetaCoreAssetGuid& materialGuid,
|
||||||
|
const MetaCoreMaterialAssetDocument& document
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::optional<MetaCoreResolvedGeneratedAssetRecord> ResolveGeneratedAsset(
|
||||||
|
const MetaCoreAssetGuid& assetGuid
|
||||||
|
) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class MetaCoreICookService : public MetaCoreIEditorService {
|
class MetaCoreICookService : public MetaCoreIEditorService {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] virtual bool CookAsset(const MetaCoreAssetGuid& assetGuid) = 0;
|
[[nodiscard]] virtual bool CookAsset(const MetaCoreAssetGuid& assetGuid) = 0;
|
||||||
|
|||||||
@ -9,7 +9,6 @@ namespace MetaCore {
|
|||||||
|
|
||||||
class MetaCoreScene;
|
class MetaCoreScene;
|
||||||
|
|
||||||
// 管理 Scene 视口交互:拾取选择与 Gizmo 变换提交。
|
|
||||||
class MetaCoreSceneInteractionService {
|
class MetaCoreSceneInteractionService {
|
||||||
public:
|
public:
|
||||||
void ResetFrameState();
|
void ResetFrameState();
|
||||||
@ -24,8 +23,6 @@ public:
|
|||||||
void ApplyViewportSelection(MetaCoreEditorContext& editorContext, MetaCoreId pickedObjectId) const;
|
void ApplyViewportSelection(MetaCoreEditorContext& editorContext, MetaCoreId pickedObjectId) const;
|
||||||
void HandleGizmoBeginUse(MetaCoreEditorContext& editorContext, bool gizmoUsing);
|
void HandleGizmoBeginUse(MetaCoreEditorContext& editorContext, bool gizmoUsing);
|
||||||
void HandleGizmoEndUse(MetaCoreEditorContext& editorContext, bool gizmoUsing);
|
void HandleGizmoEndUse(MetaCoreEditorContext& editorContext, bool gizmoUsing);
|
||||||
|
|
||||||
// Unity-style modular interactive features
|
|
||||||
void FocusSelectedObject(MetaCoreEditorContext& editorContext) const;
|
void FocusSelectedObject(MetaCoreEditorContext& editorContext) const;
|
||||||
void FocusVisibleScene(MetaCoreEditorContext& editorContext) const;
|
void FocusVisibleScene(MetaCoreEditorContext& editorContext) const;
|
||||||
void HandleGizmoManipulation(MetaCoreEditorContext& editorContext);
|
void HandleGizmoManipulation(MetaCoreEditorContext& editorContext);
|
||||||
|
|||||||
@ -35,6 +35,9 @@ struct MetaCoreTextureAssetDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string Name{};
|
std::string Name{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string StableImportKey{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::filesystem::path SourcePath{};
|
std::filesystem::path SourcePath{};
|
||||||
|
|
||||||
@ -66,6 +69,12 @@ struct MetaCoreMeshSubMeshDocument {
|
|||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::int32_t MaterialSlotIndex = -1;
|
std::int32_t MaterialSlotIndex = -1;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::uint32_t FirstIndex = 0;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::uint32_t IndexCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
@ -78,6 +87,9 @@ struct MetaCoreMeshAssetDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string Name{};
|
std::string Name{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string StableImportKey{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::int32_t VertexCount = 0;
|
std::int32_t VertexCount = 0;
|
||||||
|
|
||||||
@ -110,6 +122,9 @@ struct MetaCoreMaterialAssetDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string Name{};
|
std::string Name{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string StableImportKey{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
MetaCoreMaterialShaderModel ShaderModel = MetaCoreMaterialShaderModel::PbrMetalRough;
|
MetaCoreMaterialShaderModel ShaderModel = MetaCoreMaterialShaderModel::PbrMetalRough;
|
||||||
|
|
||||||
@ -157,6 +172,76 @@ enum class MetaCoreModelAssetKind {
|
|||||||
Generic
|
Generic
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MC_ENUM()
|
||||||
|
enum class MetaCoreModelImportUpAxis {
|
||||||
|
PreserveSource = 0,
|
||||||
|
YUp,
|
||||||
|
ZUp,
|
||||||
|
XUp
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_ENUM()
|
||||||
|
enum class MetaCoreImportMessageSeverity {
|
||||||
|
Info = 0,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_ENUM()
|
||||||
|
enum class MetaCoreModelImportResult {
|
||||||
|
Success = 0,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_STRUCT()
|
||||||
|
struct MetaCoreModelImportSettingsDocument {
|
||||||
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
float ScaleFactor = 1.0F;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreModelImportUpAxis UpAxis = MetaCoreModelImportUpAxis::PreserveSource;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
bool PreserveHierarchy = true;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
bool PreserveEmptyNodes = true;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
bool PreserveMaterialSlots = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_STRUCT()
|
||||||
|
struct MetaCoreImportMessageDocument {
|
||||||
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreImportMessageSeverity Severity = MetaCoreImportMessageSeverity::Info;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string Code{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string Message{};
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_STRUCT()
|
||||||
|
struct MetaCoreModelImportReportDocument {
|
||||||
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreModelImportResult Result = MetaCoreModelImportResult::Success;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
bool UsedFallback = false;
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::vector<MetaCoreImportMessageDocument> Messages{};
|
||||||
|
};
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
struct MetaCoreImportedGltfMeshDocument {
|
struct MetaCoreImportedGltfMeshDocument {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
@ -206,6 +291,9 @@ struct MetaCoreImportedGltfNodeDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string Name{};
|
std::string Name{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string StableNodePath{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::int32_t ParentIndex = -1;
|
std::int32_t ParentIndex = -1;
|
||||||
|
|
||||||
@ -241,6 +329,12 @@ struct MetaCoreImportedGltfAssetDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string SourceFormat{};
|
std::string SourceFormat{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreModelImportSettingsDocument ImportSettings{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreModelImportReportDocument ImportReport{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::vector<MetaCoreImportedGltfMeshDocument> Meshes{};
|
std::vector<MetaCoreImportedGltfMeshDocument> Meshes{};
|
||||||
|
|
||||||
@ -271,6 +365,9 @@ struct MetaCoreModelAssetDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string AssetType{};
|
std::string AssetType{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string RootDisplayName{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string ImporterId{};
|
std::string ImporterId{};
|
||||||
|
|
||||||
@ -286,6 +383,12 @@ struct MetaCoreModelAssetDocument {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string SourceFormat{};
|
std::string SourceFormat{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreModelImportSettingsDocument ImportSettings{};
|
||||||
|
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreModelImportReportDocument ImportReport{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::vector<MetaCoreImportedGltfMeshDocument> Meshes{};
|
std::vector<MetaCoreImportedGltfMeshDocument> Meshes{};
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,16 @@
|
|||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
// MetaCore 全局对象标识类型。
|
// Global object identifier used by MetaCore scene and runtime systems.
|
||||||
using MetaCoreId = std::uint64_t;
|
using MetaCoreId = std::uint64_t;
|
||||||
|
|
||||||
// 负责为场景对象和运行时实体分配递增标识。
|
// Allocates monotonically increasing identifiers for scene objects and runtime entities.
|
||||||
class MetaCoreIdGenerator {
|
class MetaCoreIdGenerator {
|
||||||
public:
|
public:
|
||||||
// 生成一个新的全局唯一标识。
|
// Generates a new process-local identifier.
|
||||||
static MetaCoreId Generate();
|
static MetaCoreId Generate();
|
||||||
|
|
||||||
// 确保后续生成的标识严格大于给定值。
|
// Ensures future generated identifiers are greater than the provided value.
|
||||||
static void EnsureAbove(MetaCoreId value);
|
static void EnsureAbove(MetaCoreId value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,30 +5,22 @@
|
|||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
// 定义 MetaCore 控制台消息的级别。
|
|
||||||
enum class MetaCoreLogLevel {
|
enum class MetaCoreLogLevel {
|
||||||
Info,
|
Info,
|
||||||
Warning,
|
Warning,
|
||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
|
|
||||||
// 表示一条会显示在编辑器控制台中的日志记录。
|
|
||||||
struct MetaCoreLogEntry {
|
struct MetaCoreLogEntry {
|
||||||
MetaCoreLogLevel Level = MetaCoreLogLevel::Info;
|
MetaCoreLogLevel Level = MetaCoreLogLevel::Info;
|
||||||
std::string Category;
|
std::string Category;
|
||||||
std::string Message;
|
std::string Message;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 提供最基础的日志收集能力,供编辑器控制台和调试输出复用。
|
|
||||||
class MetaCoreLogService {
|
class MetaCoreLogService {
|
||||||
public:
|
public:
|
||||||
// 写入一条新的日志。
|
|
||||||
void AddEntry(MetaCoreLogLevel level, std::string category, std::string message);
|
void AddEntry(MetaCoreLogLevel level, std::string category, std::string message);
|
||||||
|
|
||||||
// 返回当前收集到的全部日志。
|
|
||||||
[[nodiscard]] const std::vector<MetaCoreLogEntry>& GetEntries() const;
|
[[nodiscard]] const std::vector<MetaCoreLogEntry>& GetEntries() const;
|
||||||
|
|
||||||
// 清空全部日志记录。
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -189,7 +189,7 @@ bool MetaCoreWindow::Initialize(int width, int height, const std::string& title)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCoreWindowTrace("metacore.window: configure backend");
|
MetaCoreWindowTrace("metacore.window: configure runtime backend");
|
||||||
MetaCoreConfigurePanda3D(title);
|
MetaCoreConfigurePanda3D(title);
|
||||||
MetaCoreWindowTrace("metacore.window: open framework");
|
MetaCoreWindowTrace("metacore.window: open framework");
|
||||||
Impl_->Framework.open_framework();
|
Impl_->Framework.open_framework();
|
||||||
@ -200,7 +200,7 @@ bool MetaCoreWindow::Initialize(int width, int height, const std::string& title)
|
|||||||
MetaCoreWindowTrace("metacore.window: set window size");
|
MetaCoreWindowTrace("metacore.window: set window size");
|
||||||
windowProperties.set_size(width, height);
|
windowProperties.set_size(width, height);
|
||||||
|
|
||||||
MetaCoreWindowTrace("metacore.window: skip backend title due to ABI issues");
|
MetaCoreWindowTrace("metacore.window: skip runtime title handoff due to ABI issues");
|
||||||
// windowProperties.set_title(title); // This triggers bad_alloc in VS2022 Debug vs Panda3D VS2019 SDK
|
// windowProperties.set_title(title); // This triggers bad_alloc in VS2022 Debug vs Panda3D VS2019 SDK
|
||||||
|
|
||||||
MetaCoreWindowTrace("metacore.window: set foreground");
|
MetaCoreWindowTrace("metacore.window: set foreground");
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
// 定义编辑器当前阶段需要识别的按键。
|
|
||||||
enum class MetaCoreInputKey : unsigned int {
|
enum class MetaCoreInputKey : unsigned int {
|
||||||
LeftAlt = 0,
|
LeftAlt = 0,
|
||||||
RightAlt,
|
RightAlt,
|
||||||
@ -15,7 +15,6 @@ enum class MetaCoreInputKey : unsigned int {
|
|||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义编辑器当前阶段需要识别的鼠标按键。
|
|
||||||
enum class MetaCoreMouseButton : unsigned int {
|
enum class MetaCoreMouseButton : unsigned int {
|
||||||
Left = 0,
|
Left = 0,
|
||||||
Right,
|
Right,
|
||||||
@ -23,43 +22,20 @@ enum class MetaCoreMouseButton : unsigned int {
|
|||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
// 统一封装窗口层采集后的输入状态,避免上层直接依赖 Win32 或 Panda3D 细节。
|
|
||||||
class MetaCoreInput {
|
class MetaCoreInput {
|
||||||
public:
|
public:
|
||||||
// 在每帧开始时重置瞬时状态并保存上一帧快照。
|
|
||||||
void BeginFrame();
|
void BeginFrame();
|
||||||
|
|
||||||
// 由窗口层写入按键状态。
|
|
||||||
void SetKeyState(MetaCoreInputKey key, bool isDown);
|
void SetKeyState(MetaCoreInputKey key, bool isDown);
|
||||||
|
|
||||||
// 由窗口层写入鼠标按键状态。
|
|
||||||
void SetMouseButtonState(MetaCoreMouseButton button, bool isDown);
|
void SetMouseButtonState(MetaCoreMouseButton button, bool isDown);
|
||||||
|
|
||||||
// 由窗口层写入当前鼠标位置。
|
|
||||||
void SetCursorPosition(const glm::vec2& cursorPosition);
|
void SetCursorPosition(const glm::vec2& cursorPosition);
|
||||||
|
|
||||||
// 由窗口消息累加滚轮值,正值表示向前滚动。
|
|
||||||
void AddMouseWheelDelta(float delta);
|
void AddMouseWheelDelta(float delta);
|
||||||
|
|
||||||
// 判断按键当前是否处于按下状态。
|
|
||||||
[[nodiscard]] bool IsKeyDown(MetaCoreInputKey key) const;
|
[[nodiscard]] bool IsKeyDown(MetaCoreInputKey key) const;
|
||||||
|
|
||||||
// 判断按键是否在本帧刚刚按下。
|
|
||||||
[[nodiscard]] bool WasKeyPressed(MetaCoreInputKey key) const;
|
[[nodiscard]] bool WasKeyPressed(MetaCoreInputKey key) const;
|
||||||
|
|
||||||
// 判断鼠标按键当前是否按下。
|
|
||||||
[[nodiscard]] bool IsMouseButtonDown(MetaCoreMouseButton button) const;
|
[[nodiscard]] bool IsMouseButtonDown(MetaCoreMouseButton button) const;
|
||||||
|
|
||||||
// 判断鼠标按键是否在本帧刚刚按下。
|
|
||||||
[[nodiscard]] bool WasMouseButtonPressed(MetaCoreMouseButton button) const;
|
[[nodiscard]] bool WasMouseButtonPressed(MetaCoreMouseButton button) const;
|
||||||
|
|
||||||
// 返回当前帧累计的滚轮值。
|
|
||||||
[[nodiscard]] float GetMouseWheelDelta() const;
|
[[nodiscard]] float GetMouseWheelDelta() const;
|
||||||
|
|
||||||
// 返回当前鼠标位置。
|
|
||||||
[[nodiscard]] const glm::vec2& GetCursorPosition() const;
|
[[nodiscard]] const glm::vec2& GetCursorPosition() const;
|
||||||
|
|
||||||
// 返回相对上一帧的鼠标位移。
|
|
||||||
[[nodiscard]] const glm::vec2& GetCursorDelta() const;
|
[[nodiscard]] const glm::vec2& GetCursorDelta() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -12,10 +12,8 @@ namespace MetaCore {
|
|||||||
|
|
||||||
class MetaCoreRenderDevice;
|
class MetaCoreRenderDevice;
|
||||||
|
|
||||||
// 定义宿主窗口层向上暴露的原生消息回调,用于把 Win32 消息转交给 ImGui。
|
|
||||||
using MetaCoreNativeWindowMessageHandler = std::function<bool(void*, unsigned int, std::uintptr_t, std::intptr_t)>;
|
using MetaCoreNativeWindowMessageHandler = std::function<bool(void*, unsigned int, std::uintptr_t, std::intptr_t)>;
|
||||||
|
|
||||||
// 封装 Panda3D 窗口、时间步进与基础输入采集。
|
|
||||||
class MetaCoreWindow {
|
class MetaCoreWindow {
|
||||||
public:
|
public:
|
||||||
class MetaCoreWindowImpl;
|
class MetaCoreWindowImpl;
|
||||||
@ -23,50 +21,25 @@ public:
|
|||||||
MetaCoreWindow();
|
MetaCoreWindow();
|
||||||
~MetaCoreWindow();
|
~MetaCoreWindow();
|
||||||
|
|
||||||
// 创建 Panda3D 主窗口并准备输入采集。
|
|
||||||
bool Initialize(int width, int height, const std::string& title);
|
bool Initialize(int width, int height, const std::string& title);
|
||||||
|
|
||||||
// 释放窗口与 Panda3D 宿主资源。
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
// 处理窗口事件、更新时间步进并刷新输入状态。
|
|
||||||
void BeginFrame();
|
void BeginFrame();
|
||||||
|
|
||||||
// 为未来扩展保留的帧结束入口。
|
|
||||||
void EndFrame();
|
void EndFrame();
|
||||||
|
|
||||||
// 返回窗口是否请求退出。
|
|
||||||
[[nodiscard]] bool ShouldClose() const;
|
[[nodiscard]] bool ShouldClose() const;
|
||||||
|
|
||||||
// 主动请求窗口退出。
|
|
||||||
void RequestClose();
|
void RequestClose();
|
||||||
|
|
||||||
// 返回原生窗口句柄,供 ImGui Win32 backend 初始化使用。
|
|
||||||
[[nodiscard]] void* GetNativeWindowHandle() const;
|
[[nodiscard]] void* GetNativeWindowHandle() const;
|
||||||
|
|
||||||
// 返回 PandaFramework 原生对象指针,仅供底层桥接层使用。
|
|
||||||
[[nodiscard]] void* GetNativeFrameworkHandle() const;
|
[[nodiscard]] void* GetNativeFrameworkHandle() const;
|
||||||
|
|
||||||
// 返回 WindowFramework 原生对象指针,仅供底层桥接层使用。
|
|
||||||
[[nodiscard]] void* GetNativeWindowFrameworkHandle() const;
|
[[nodiscard]] void* GetNativeWindowFrameworkHandle() const;
|
||||||
|
|
||||||
// 返回 GraphicsWindow 原生对象指针,仅供底层桥接层使用。
|
|
||||||
[[nodiscard]] void* GetNativeGraphicsWindowHandle() const;
|
[[nodiscard]] void* GetNativeGraphicsWindowHandle() const;
|
||||||
|
|
||||||
// 返回当前输入对象。
|
|
||||||
[[nodiscard]] MetaCoreInput& GetInput();
|
[[nodiscard]] MetaCoreInput& GetInput();
|
||||||
[[nodiscard]] const MetaCoreInput& GetInput() const;
|
[[nodiscard]] const MetaCoreInput& GetInput() const;
|
||||||
|
|
||||||
// 返回当前帧耗时,单位为秒。
|
|
||||||
[[nodiscard]] float GetDeltaSeconds() const;
|
[[nodiscard]] float GetDeltaSeconds() const;
|
||||||
|
|
||||||
// 返回当前窗口尺寸。
|
|
||||||
[[nodiscard]] std::pair<int, int> GetWindowSize() const;
|
[[nodiscard]] std::pair<int, int> GetWindowSize() const;
|
||||||
|
|
||||||
// 返回当前帧缓冲尺寸。
|
|
||||||
[[nodiscard]] std::pair<int, int> GetFramebufferSize() const;
|
[[nodiscard]] std::pair<int, int> GetFramebufferSize() const;
|
||||||
|
|
||||||
// 注册原生消息回调。
|
|
||||||
void SetNativeWindowMessageHandler(MetaCoreNativeWindowMessageHandler handler);
|
void SetNativeWindowMessageHandler(MetaCoreNativeWindowMessageHandler handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -63,12 +63,12 @@ bool MetaCoreEditorViewportRenderer::Initialize(MetaCoreRenderDevice& renderDevi
|
|||||||
MetaCoreTrace("metacore.render: viewport init enter");
|
MetaCoreTrace("metacore.render: viewport init enter");
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
|
||||||
MetaCoreTrace("metacore.render: viewport scene bridge begin");
|
MetaCoreTrace("metacore.render: viewport scene runtime bind begin");
|
||||||
if (!SceneBridge_.Initialize(renderDevice)) {
|
if (!SceneBridge_.Initialize(renderDevice)) {
|
||||||
MetaCoreTrace("metacore.render: viewport scene bridge failed");
|
MetaCoreTrace("metacore.render: viewport scene runtime bind failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MetaCoreTrace("metacore.render: viewport scene bridge done");
|
MetaCoreTrace("metacore.render: viewport scene runtime ready");
|
||||||
|
|
||||||
RenderDevice_ = &renderDevice;
|
RenderDevice_ = &renderDevice;
|
||||||
ViewportRect_ = MetaCoreViewportRect{};
|
ViewportRect_ = MetaCoreViewportRect{};
|
||||||
@ -108,20 +108,13 @@ void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene&
|
|||||||
RenderDevice_->SetSceneViewportRect(ViewportRect_);
|
RenderDevice_->SetSceneViewportRect(ViewportRect_);
|
||||||
SceneBridge_.ApplySceneView(sceneView);
|
SceneBridge_.ApplySceneView(sceneView);
|
||||||
#if defined(_DEBUG)
|
#if defined(_DEBUG)
|
||||||
if (!DebugSceneSyncOverrideEnabled_) {
|
static bool loggedDebugRenderableSync = false;
|
||||||
(void)scene;
|
|
||||||
static bool loggedDebugSyncSkip = false;
|
|
||||||
SceneSyncDegraded_ = true;
|
|
||||||
if (!loggedDebugSyncSkip) {
|
|
||||||
MetaCoreTrace("metacore.render: skipping debug scene sync due to backend runtime instability");
|
|
||||||
loggedDebugSyncSkip = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
SceneSyncDegraded_ = false;
|
SceneSyncDegraded_ = false;
|
||||||
SceneBridge_.SyncScene(scene);
|
if (!loggedDebugRenderableSync) {
|
||||||
|
MetaCoreTrace("metacore.render: debug scene sync active; syncing renderable objects to the MetaCore viewport");
|
||||||
|
loggedDebugRenderableSync = true;
|
||||||
|
}
|
||||||
|
SceneBridge_.SyncScene(scene, true);
|
||||||
if (SceneBridge_.HasRuntimeSyncFailure()) {
|
if (SceneBridge_.HasRuntimeSyncFailure()) {
|
||||||
SceneSyncDegraded_ = true;
|
SceneSyncDegraded_ = true;
|
||||||
LastSceneSyncFailure_ = SceneBridge_.GetLastRuntimeSyncFailure();
|
LastSceneSyncFailure_ = SceneBridge_.GetLastRuntimeSyncFailure();
|
||||||
@ -133,6 +126,22 @@ void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene&
|
|||||||
LastSceneSyncFailure_.clear();
|
LastSceneSyncFailure_.clear();
|
||||||
HasLoggedSceneSyncFailure_ = false;
|
HasLoggedSceneSyncFailure_ = false;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
SceneSyncDegraded_ = false;
|
||||||
|
SceneBridge_.SyncScene(scene, false);
|
||||||
|
if (SceneBridge_.HasRuntimeSyncFailure()) {
|
||||||
|
SceneSyncDegraded_ = true;
|
||||||
|
LastSceneSyncFailure_ = SceneBridge_.GetLastRuntimeSyncFailure();
|
||||||
|
if (!HasLoggedSceneSyncFailure_) {
|
||||||
|
MetaCoreTrace(("metacore.render: scene sync degraded after runtime failure: " + LastSceneSyncFailure_).c_str());
|
||||||
|
HasLoggedSceneSyncFailure_ = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LastSceneSyncFailure_.clear();
|
||||||
|
HasLoggedSceneSyncFailure_ = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaCoreEditorViewportRenderer::SetProjectRootPath(const std::filesystem::path& projectRootPath) {
|
void MetaCoreEditorViewportRenderer::SetProjectRootPath(const std::filesystem::path& projectRootPath) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -3,33 +3,23 @@
|
|||||||
#include "MetaCoreRender/MetaCorePandaSceneBridge.h"
|
#include "MetaCoreRender/MetaCorePandaSceneBridge.h"
|
||||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
class MetaCoreRenderDevice;
|
class MetaCoreRenderDevice;
|
||||||
class MetaCoreScene;
|
class MetaCoreScene;
|
||||||
|
|
||||||
// 管理编辑器中央场景面板与 Panda3D DisplayRegion 之间的同步。
|
|
||||||
class MetaCoreEditorViewportRenderer {
|
class MetaCoreEditorViewportRenderer {
|
||||||
public:
|
public:
|
||||||
// 初始化 Panda3D 场景桥接与显示区域驱动。
|
|
||||||
bool Initialize(MetaCoreRenderDevice& renderDevice);
|
bool Initialize(MetaCoreRenderDevice& renderDevice);
|
||||||
|
|
||||||
// 释放桥接层与内部缓存。
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
// 写入当前 Scene 面板像素矩形。
|
|
||||||
void SetViewportRect(const MetaCoreViewportRect& viewportRect);
|
void SetViewportRect(const MetaCoreViewportRect& viewportRect);
|
||||||
|
|
||||||
// 将场景状态同步到 Panda3D,并更新编辑器相机。
|
|
||||||
void RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView);
|
void RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView);
|
||||||
|
|
||||||
// 设置当前项目根目录,用于模型加载时解析绝对路径。
|
|
||||||
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
|
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
|
||||||
|
|
||||||
// 返回 Panda3D 中对象当前真实使用的世界矩阵。
|
|
||||||
[[nodiscard]] bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const;
|
[[nodiscard]] bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const;
|
||||||
|
|
||||||
// 当前是否处于 Debug 兼容降级模式。
|
|
||||||
[[nodiscard]] bool IsSceneSyncDegraded() const;
|
[[nodiscard]] bool IsSceneSyncDegraded() const;
|
||||||
[[nodiscard]] bool IsDebugSceneSyncOverrideEnabled() const;
|
[[nodiscard]] bool IsDebugSceneSyncOverrideEnabled() const;
|
||||||
[[nodiscard]] const std::string& GetLastSceneSyncFailure() const;
|
[[nodiscard]] const std::string& GetLastSceneSyncFailure() const;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
@ -13,29 +14,17 @@ class MetaCoreRenderDevice;
|
|||||||
class MetaCoreScene;
|
class MetaCoreScene;
|
||||||
struct MetaCoreSceneView;
|
struct MetaCoreSceneView;
|
||||||
|
|
||||||
// 负责在 MetaCoreScene 与 Panda3D NodePath 场景之间建立同步关系。
|
|
||||||
class MetaCorePandaSceneBridge {
|
class MetaCorePandaSceneBridge {
|
||||||
public:
|
public:
|
||||||
MetaCorePandaSceneBridge();
|
MetaCorePandaSceneBridge();
|
||||||
~MetaCorePandaSceneBridge();
|
~MetaCorePandaSceneBridge();
|
||||||
|
|
||||||
// 准备 Panda3D 场景根节点、调试网格与编辑器相机。
|
|
||||||
bool Initialize(MetaCoreRenderDevice& renderDevice);
|
bool Initialize(MetaCoreRenderDevice& renderDevice);
|
||||||
|
|
||||||
// 释放桥接层创建的 Panda3D 节点。
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
// 设置当前项目根目录,用于解析资源文件的绝对路径。
|
|
||||||
// 必须在项目加载后调用,否则模型加载会失败退化为立方体。
|
|
||||||
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
|
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
|
||||||
|
void SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly = false);
|
||||||
// 将 MetaCoreScene 当前状态同步到 Panda3D 场景图。
|
|
||||||
void SyncScene(const MetaCoreScene& scene);
|
|
||||||
|
|
||||||
// 更新编辑器相机与当前选中对象高亮状态。
|
|
||||||
void ApplySceneView(const MetaCoreSceneView& sceneView);
|
void ApplySceneView(const MetaCoreSceneView& sceneView);
|
||||||
|
|
||||||
// 返回 Panda3D 场景中对象当前真实使用的世界矩阵。
|
|
||||||
[[nodiscard]] bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const;
|
[[nodiscard]] bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const;
|
||||||
[[nodiscard]] bool HasRuntimeSyncFailure() const;
|
[[nodiscard]] bool HasRuntimeSyncFailure() const;
|
||||||
[[nodiscard]] const std::string& GetLastRuntimeSyncFailure() const;
|
[[nodiscard]] const std::string& GetLastRuntimeSyncFailure() const;
|
||||||
|
|||||||
@ -12,37 +12,20 @@ class MetaCoreEditorViewportRenderer;
|
|||||||
class MetaCorePandaSceneBridge;
|
class MetaCorePandaSceneBridge;
|
||||||
class MetaCoreWindow;
|
class MetaCoreWindow;
|
||||||
|
|
||||||
// 封装 Panda3D 图形引擎、主窗口和中央场景显示区域。
|
|
||||||
class MetaCoreRenderDevice {
|
class MetaCoreRenderDevice {
|
||||||
public:
|
public:
|
||||||
MetaCoreRenderDevice();
|
MetaCoreRenderDevice();
|
||||||
~MetaCoreRenderDevice();
|
~MetaCoreRenderDevice();
|
||||||
|
|
||||||
// 绑定 Panda3D 窗口与图形引擎,准备后续场景渲染。
|
|
||||||
bool Initialize(MetaCoreWindow& window);
|
bool Initialize(MetaCoreWindow& window);
|
||||||
|
|
||||||
// 释放 Panda3D 渲染相关资源。
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
// 提交 Panda3D 场景绘制。
|
|
||||||
void RenderFrame() const;
|
void RenderFrame() const;
|
||||||
|
|
||||||
// 提交当前帧翻转,确保 ImGui 叠加结果显示出来。
|
|
||||||
void PresentFrame() const;
|
void PresentFrame() const;
|
||||||
|
|
||||||
// 根据 ImGui 场景面板像素矩形更新 Panda3D DisplayRegion。
|
|
||||||
void SetSceneViewportRect(const MetaCoreViewportRect& viewportRect);
|
void SetSceneViewportRect(const MetaCoreViewportRect& viewportRect);
|
||||||
|
|
||||||
// 返回 WindowFramework 原生对象指针,仅供 Panda3D 桥接层使用。
|
|
||||||
[[nodiscard]] void* GetNativeWindowFrameworkHandle() const;
|
[[nodiscard]] void* GetNativeWindowFrameworkHandle() const;
|
||||||
|
|
||||||
// 返回场景根节点原生对象指针,仅供 Panda3D 桥接层使用。
|
|
||||||
[[nodiscard]] void* GetNativeSceneRootHandle() const;
|
[[nodiscard]] void* GetNativeSceneRootHandle() const;
|
||||||
|
|
||||||
// 返回编辑器相机节点原生对象指针,仅供 Panda3D 桥接层使用。
|
|
||||||
[[nodiscard]] void* GetNativeEditorCameraHandle() const;
|
[[nodiscard]] void* GetNativeEditorCameraHandle() const;
|
||||||
|
|
||||||
// 返回 Panda3D 当前真实使用的编辑器相机视图矩阵和投影矩阵。
|
|
||||||
[[nodiscard]] bool TryGetEditorCameraMatrices(glm::mat4& viewMatrix, glm::mat4& projectionMatrix) const;
|
[[nodiscard]] bool TryGetEditorCameraMatrices(glm::mat4& viewMatrix, glm::mat4& projectionMatrix) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
// 描述场景在宿主窗口中的像素矩形区域。
|
|
||||||
struct MetaCoreViewportRect {
|
struct MetaCoreViewportRect {
|
||||||
float Left = 0.0F;
|
float Left = 0.0F;
|
||||||
float Top = 0.0F;
|
float Top = 0.0F;
|
||||||
@ -14,7 +13,6 @@ struct MetaCoreViewportRect {
|
|||||||
float Height = 1.0F;
|
float Height = 1.0F;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 描述一次 Panda3D 场景同步所需的相机与选择参数。
|
|
||||||
struct MetaCoreSceneView {
|
struct MetaCoreSceneView {
|
||||||
glm::vec3 CameraPosition{0.0F, 2.2F, 6.5F};
|
glm::vec3 CameraPosition{0.0F, 2.2F, 6.5F};
|
||||||
glm::vec3 CameraTarget{0.0F, 0.7F, 0.0F};
|
glm::vec3 CameraTarget{0.0F, 0.7F, 0.0F};
|
||||||
@ -23,7 +21,6 @@ struct MetaCoreSceneView {
|
|||||||
MetaCoreId SelectedObjectId = 0;
|
MetaCoreId SelectedObjectId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义二进制网格顶点的内存布局,必须与导入器(MetaCoreBuiltinCoreServicesModule)中的定义严格一致。
|
|
||||||
struct MetaCoreMeshVertex {
|
struct MetaCoreMeshVertex {
|
||||||
float px, py, pz;
|
float px, py, pz;
|
||||||
float nx, ny, nz;
|
float nx, ny, nz;
|
||||||
|
|||||||
@ -31,8 +31,8 @@ void MetaCoreRuntimeDataDispatcher::ApplyUpdates(const std::vector<MetaCoreRunti
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCoreGameObject* gameObject = Scene_.FindGameObject(bindingDefinition.TargetObjectId);
|
MetaCoreGameObject gameObject = Scene_.FindGameObject(bindingDefinition.TargetObjectId);
|
||||||
if (gameObject == nullptr) {
|
if (!gameObject) {
|
||||||
MarkBindingFault(bindingDefinition.BindingId, "Target object missing");
|
MarkBindingFault(bindingDefinition.BindingId, "Target object missing");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -41,31 +41,31 @@ void MetaCoreRuntimeDataDispatcher::ApplyUpdates(const std::vector<MetaCoreRunti
|
|||||||
switch (bindingDefinition.Target) {
|
switch (bindingDefinition.Target) {
|
||||||
case MetaCoreRuntimeBindingTarget::TransformPosition:
|
case MetaCoreRuntimeBindingTarget::TransformPosition:
|
||||||
if (update.Value.Type == MetaCoreRuntimeValueType::Vec3) {
|
if (update.Value.Type == MetaCoreRuntimeValueType::Vec3) {
|
||||||
gameObject->Transform.Position = update.Value.Vec3Value;
|
gameObject.GetComponent<MetaCoreTransformComponent>().Position = update.Value.Vec3Value;
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MetaCoreRuntimeBindingTarget::MeshRendererVisible:
|
case MetaCoreRuntimeBindingTarget::MeshRendererVisible:
|
||||||
if (update.Value.Type == MetaCoreRuntimeValueType::Bool && gameObject->MeshRenderer.has_value()) {
|
if (update.Value.Type == MetaCoreRuntimeValueType::Bool && gameObject.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||||||
gameObject->MeshRenderer->Visible = update.Value.BoolValue;
|
gameObject.GetComponent<MetaCoreMeshRendererComponent>().Visible = update.Value.BoolValue;
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MetaCoreRuntimeBindingTarget::MeshRendererBaseColor:
|
case MetaCoreRuntimeBindingTarget::MeshRendererBaseColor:
|
||||||
if (update.Value.Type == MetaCoreRuntimeValueType::Vec3 && gameObject->MeshRenderer.has_value()) {
|
if (update.Value.Type == MetaCoreRuntimeValueType::Vec3 && gameObject.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||||||
gameObject->MeshRenderer->BaseColor = update.Value.Vec3Value;
|
gameObject.GetComponent<MetaCoreMeshRendererComponent>().BaseColor = update.Value.Vec3Value;
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MetaCoreRuntimeBindingTarget::LightIntensity:
|
case MetaCoreRuntimeBindingTarget::LightIntensity:
|
||||||
if (update.Value.Type == MetaCoreRuntimeValueType::Double && gameObject->Light.has_value()) {
|
if (update.Value.Type == MetaCoreRuntimeValueType::Double && gameObject.HasComponent<MetaCoreLightComponent>()) {
|
||||||
gameObject->Light->Intensity = static_cast<float>(update.Value.DoubleValue);
|
gameObject.GetComponent<MetaCoreLightComponent>().Intensity = static_cast<float>(update.Value.DoubleValue);
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MetaCoreRuntimeBindingTarget::LightColor:
|
case MetaCoreRuntimeBindingTarget::LightColor:
|
||||||
if (update.Value.Type == MetaCoreRuntimeValueType::Vec3 && gameObject->Light.has_value()) {
|
if (update.Value.Type == MetaCoreRuntimeValueType::Vec3 && gameObject.HasComponent<MetaCoreLightComponent>()) {
|
||||||
gameObject->Light->Color = update.Value.Vec3Value;
|
gameObject.GetComponent<MetaCoreLightComponent>().Color = update.Value.Vec3Value;
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -41,50 +41,63 @@ std::string MetaCoreBuildCopyName(const std::string& name) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MetaCoreGameObject& MetaCoreScene::CreateGameObject(const std::string& name, MetaCoreId parentId) {
|
MetaCoreGameObject MetaCoreScene::CreateGameObject(const std::string& name, MetaCoreId parentId) {
|
||||||
GameObjects_.push_back(MetaCoreGameObject{
|
return CreateGameObjectWithId(MetaCoreIdGenerator::Generate(), name, parentId);
|
||||||
MetaCoreIdGenerator::Generate(),
|
|
||||||
parentId,
|
|
||||||
name,
|
|
||||||
MetaCoreTransformComponent{},
|
|
||||||
std::nullopt,
|
|
||||||
std::nullopt,
|
|
||||||
std::nullopt
|
|
||||||
});
|
|
||||||
return GameObjects_.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCoreGameObject* MetaCoreScene::FindGameObject(MetaCoreId objectId) {
|
MetaCoreGameObject MetaCoreScene::CreateGameObjectWithId(MetaCoreId id, const std::string& name, MetaCoreId parentId) {
|
||||||
for (MetaCoreGameObject& object : GameObjects_) {
|
entt::entity entity = Registry_.create();
|
||||||
if (object.Id == objectId) {
|
IdToEntity_[id] = entity;
|
||||||
return &object;
|
|
||||||
}
|
MetaCoreGameObject obj(entity, this);
|
||||||
|
obj.AddComponent<MetaCoreIdComponent>().Id = id;
|
||||||
|
obj.AddComponent<MetaCoreNameComponent>().Name = name;
|
||||||
|
obj.AddComponent<MetaCoreHierarchyComponent>().ParentId = parentId;
|
||||||
|
obj.AddComponent<MetaCoreTransformComponent>();
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaCoreGameObject MetaCoreScene::FindGameObject(MetaCoreId objectId) {
|
||||||
|
auto it = IdToEntity_.find(objectId);
|
||||||
|
if (it != IdToEntity_.end()) {
|
||||||
|
return MetaCoreGameObject(it->second, this);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return MetaCoreGameObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaCoreGameObject* MetaCoreScene::FindGameObject(MetaCoreId objectId) const {
|
MetaCoreGameObject MetaCoreScene::FindGameObject(MetaCoreId objectId) const {
|
||||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
auto it = IdToEntity_.find(objectId);
|
||||||
if (object.Id == objectId) {
|
if (it != IdToEntity_.end()) {
|
||||||
return &object;
|
return MetaCoreGameObject(it->second, const_cast<MetaCoreScene*>(this));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return MetaCoreGameObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MetaCoreGameObject>& MetaCoreScene::GetGameObjects() {
|
std::vector<MetaCoreGameObject> MetaCoreScene::GetGameObjects() {
|
||||||
return GameObjects_;
|
std::vector<MetaCoreGameObject> objects;
|
||||||
|
objects.reserve(IdToEntity_.size());
|
||||||
|
for (auto [id, entity] : IdToEntity_) {
|
||||||
|
objects.emplace_back(entity, this);
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<MetaCoreGameObject>& MetaCoreScene::GetGameObjects() const {
|
std::vector<MetaCoreGameObject> MetaCoreScene::GetGameObjects() const {
|
||||||
return GameObjects_;
|
std::vector<MetaCoreGameObject> objects;
|
||||||
|
objects.reserve(IdToEntity_.size());
|
||||||
|
for (auto [id, entity] : IdToEntity_) {
|
||||||
|
objects.emplace_back(entity, const_cast<MetaCoreScene*>(this));
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MetaCoreId> MetaCoreScene::GetRootObjectIds() const {
|
std::vector<MetaCoreId> MetaCoreScene::GetRootObjectIds() const {
|
||||||
std::vector<MetaCoreId> rootIds;
|
std::vector<MetaCoreId> rootIds;
|
||||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
auto view = Registry_.view<MetaCoreIdComponent, MetaCoreHierarchyComponent>();
|
||||||
if (object.ParentId == 0) {
|
for (auto entity : view) {
|
||||||
rootIds.push_back(object.Id);
|
if (view.get<MetaCoreHierarchyComponent>(entity).ParentId == 0) {
|
||||||
|
rootIds.push_back(view.get<MetaCoreIdComponent>(entity).Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rootIds;
|
return rootIds;
|
||||||
@ -92,16 +105,17 @@ std::vector<MetaCoreId> MetaCoreScene::GetRootObjectIds() const {
|
|||||||
|
|
||||||
std::vector<MetaCoreId> MetaCoreScene::GetChildrenOf(MetaCoreId parentId) const {
|
std::vector<MetaCoreId> MetaCoreScene::GetChildrenOf(MetaCoreId parentId) const {
|
||||||
std::vector<MetaCoreId> childIds;
|
std::vector<MetaCoreId> childIds;
|
||||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
auto view = Registry_.view<MetaCoreIdComponent, MetaCoreHierarchyComponent>();
|
||||||
if (object.ParentId == parentId) {
|
for (auto entity : view) {
|
||||||
childIds.push_back(object.Id);
|
if (view.get<MetaCoreHierarchyComponent>(entity).ParentId == parentId) {
|
||||||
|
childIds.push_back(view.get<MetaCoreIdComponent>(entity).Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return childIds;
|
return childIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaCoreScene::CollectPreorder(MetaCoreId objectId, std::vector<MetaCoreId>& output) const {
|
void MetaCoreScene::CollectPreorder(MetaCoreId objectId, std::vector<MetaCoreId>& output) const {
|
||||||
if (FindGameObject(objectId) == nullptr) {
|
if (!FindGameObject(objectId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,30 +144,30 @@ bool MetaCoreScene::IsDescendantOf(MetaCoreId objectId, MetaCoreId ancestorId) c
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaCoreGameObject* currentObject = FindGameObject(objectId);
|
MetaCoreGameObject currentObject = FindGameObject(objectId);
|
||||||
while (currentObject != nullptr && currentObject->ParentId != 0) {
|
while (currentObject && currentObject.GetParentId() != 0) {
|
||||||
if (currentObject->ParentId == ancestorId) {
|
if (currentObject.GetParentId() == ancestorId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
currentObject = FindGameObject(currentObject->ParentId);
|
currentObject = FindGameObject(currentObject.GetParentId());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreScene::RenameGameObject(MetaCoreId objectId, const std::string& name) {
|
bool MetaCoreScene::RenameGameObject(MetaCoreId objectId, const std::string& name) {
|
||||||
MetaCoreGameObject* object = FindGameObject(objectId);
|
MetaCoreGameObject object = FindGameObject(objectId);
|
||||||
if (object == nullptr || name.empty()) {
|
if (!object || name.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
object->Name = name;
|
object.GetName() = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MetaCoreId> MetaCoreScene::DeleteGameObjects(const std::vector<MetaCoreId>& objectIds) {
|
std::vector<MetaCoreId> MetaCoreScene::DeleteGameObjects(const std::vector<MetaCoreId>& objectIds) {
|
||||||
std::unordered_set<MetaCoreId> selectedIds;
|
std::unordered_set<MetaCoreId> selectedIds;
|
||||||
for (MetaCoreId objectId : objectIds) {
|
for (MetaCoreId objectId : objectIds) {
|
||||||
if (FindGameObject(objectId) != nullptr) {
|
if (FindGameObject(objectId)) {
|
||||||
selectedIds.insert(objectId);
|
selectedIds.insert(objectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,14 +179,14 @@ std::vector<MetaCoreId> MetaCoreScene::DeleteGameObjects(const std::vector<MetaC
|
|||||||
std::vector<MetaCoreId> rootIds;
|
std::vector<MetaCoreId> rootIds;
|
||||||
rootIds.reserve(selectedIds.size());
|
rootIds.reserve(selectedIds.size());
|
||||||
for (MetaCoreId objectId : selectedIds) {
|
for (MetaCoreId objectId : selectedIds) {
|
||||||
const MetaCoreGameObject* object = FindGameObject(objectId);
|
MetaCoreGameObject object = FindGameObject(objectId);
|
||||||
bool hasSelectedAncestor = false;
|
bool hasSelectedAncestor = false;
|
||||||
while (object != nullptr && object->ParentId != 0) {
|
while (object && object.GetParentId() != 0) {
|
||||||
if (selectedIds.contains(object->ParentId)) {
|
if (selectedIds.contains(object.GetParentId())) {
|
||||||
hasSelectedAncestor = true;
|
hasSelectedAncestor = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
object = FindGameObject(object->ParentId);
|
object = FindGameObject(object.GetParentId());
|
||||||
}
|
}
|
||||||
if (!hasSelectedAncestor) {
|
if (!hasSelectedAncestor) {
|
||||||
rootIds.push_back(objectId);
|
rootIds.push_back(objectId);
|
||||||
@ -188,20 +202,23 @@ std::vector<MetaCoreId> MetaCoreScene::DeleteGameObjects(const std::vector<MetaC
|
|||||||
|
|
||||||
std::vector<MetaCoreId> deletedIds;
|
std::vector<MetaCoreId> deletedIds;
|
||||||
deletedIds.reserve(idsToDelete.size());
|
deletedIds.reserve(idsToDelete.size());
|
||||||
std::erase_if(GameObjects_, [&](const MetaCoreGameObject& object) {
|
|
||||||
if (!idsToDelete.contains(object.Id)) {
|
for (MetaCoreId id : idsToDelete) {
|
||||||
return false;
|
auto it = IdToEntity_.find(id);
|
||||||
|
if (it != IdToEntity_.end()) {
|
||||||
|
Registry_.destroy(it->second);
|
||||||
|
IdToEntity_.erase(it);
|
||||||
|
deletedIds.push_back(id);
|
||||||
}
|
}
|
||||||
deletedIds.push_back(object.Id);
|
}
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return deletedIds;
|
return deletedIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MetaCoreId> MetaCoreScene::DuplicateGameObjects(const std::vector<MetaCoreId>& objectIds) {
|
std::vector<MetaCoreId> MetaCoreScene::DuplicateGameObjects(const std::vector<MetaCoreId>& objectIds) {
|
||||||
std::unordered_set<MetaCoreId> selectedIds;
|
std::unordered_set<MetaCoreId> selectedIds;
|
||||||
for (MetaCoreId objectId : objectIds) {
|
for (MetaCoreId objectId : objectIds) {
|
||||||
if (FindGameObject(objectId) != nullptr) {
|
if (FindGameObject(objectId)) {
|
||||||
selectedIds.insert(objectId);
|
selectedIds.insert(objectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,14 +234,14 @@ std::vector<MetaCoreId> MetaCoreScene::DuplicateGameObjects(const std::vector<Me
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaCoreGameObject* object = FindGameObject(objectId);
|
MetaCoreGameObject object = FindGameObject(objectId);
|
||||||
bool hasSelectedAncestor = false;
|
bool hasSelectedAncestor = false;
|
||||||
while (object != nullptr && object->ParentId != 0) {
|
while (object && object.GetParentId() != 0) {
|
||||||
if (selectedIds.contains(object->ParentId)) {
|
if (selectedIds.contains(object.GetParentId())) {
|
||||||
hasSelectedAncestor = true;
|
hasSelectedAncestor = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
object = FindGameObject(object->ParentId);
|
object = FindGameObject(object.GetParentId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSelectedAncestor) {
|
if (!hasSelectedAncestor) {
|
||||||
@ -232,52 +249,61 @@ std::vector<MetaCoreId> MetaCoreScene::DuplicateGameObjects(const std::vector<Me
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MetaCoreGameObject> clonedObjects;
|
|
||||||
std::vector<MetaCoreId> duplicatedRootIds;
|
std::vector<MetaCoreId> duplicatedRootIds;
|
||||||
|
|
||||||
const auto cloneSubtree = [&](const auto& self, MetaCoreId sourceId, MetaCoreId duplicatedParentId, bool isRoot) -> void {
|
const auto cloneSubtree = [&](const auto& self, MetaCoreId sourceId, MetaCoreId duplicatedParentId, bool isRoot) -> void {
|
||||||
const MetaCoreGameObject* sourceObject = FindGameObject(sourceId);
|
MetaCoreGameObject sourceObject = FindGameObject(sourceId);
|
||||||
if (sourceObject == nullptr) {
|
if (!sourceObject) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCoreGameObject clonedObject = *sourceObject;
|
MetaCoreId newId = MetaCoreIdGenerator::Generate();
|
||||||
clonedObject.Id = MetaCoreIdGenerator::Generate();
|
std::string newName = isRoot ? MetaCoreBuildCopyName(sourceObject.GetName()) : sourceObject.GetName();
|
||||||
clonedObject.ParentId = duplicatedParentId;
|
MetaCoreGameObject clonedObject = CreateGameObjectWithId(newId, newName, duplicatedParentId);
|
||||||
|
|
||||||
|
clonedObject.GetComponent<MetaCoreTransformComponent>() = sourceObject.GetComponent<MetaCoreTransformComponent>();
|
||||||
|
|
||||||
|
if (sourceObject.HasComponent<MetaCoreCameraComponent>())
|
||||||
|
clonedObject.AddComponent<MetaCoreCameraComponent>(sourceObject.GetComponent<MetaCoreCameraComponent>());
|
||||||
|
|
||||||
|
if (sourceObject.HasComponent<MetaCoreMeshRendererComponent>())
|
||||||
|
clonedObject.AddComponent<MetaCoreMeshRendererComponent>(sourceObject.GetComponent<MetaCoreMeshRendererComponent>());
|
||||||
|
|
||||||
|
if (sourceObject.HasComponent<MetaCoreLightComponent>())
|
||||||
|
clonedObject.AddComponent<MetaCoreLightComponent>(sourceObject.GetComponent<MetaCoreLightComponent>());
|
||||||
|
|
||||||
|
if (sourceObject.HasComponent<MetaCorePrefabInstanceMetadata>())
|
||||||
|
clonedObject.AddComponent<MetaCorePrefabInstanceMetadata>(sourceObject.GetComponent<MetaCorePrefabInstanceMetadata>());
|
||||||
|
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
clonedObject.Name = MetaCoreBuildCopyName(sourceObject->Name);
|
duplicatedRootIds.push_back(newId);
|
||||||
duplicatedRootIds.push_back(clonedObject.Id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clonedObjects.push_back(std::move(clonedObject));
|
|
||||||
const MetaCoreId newObjectId = clonedObjects.back().Id;
|
|
||||||
|
|
||||||
for (MetaCoreId childId : GetChildrenOf(sourceId)) {
|
for (MetaCoreId childId : GetChildrenOf(sourceId)) {
|
||||||
self(self, childId, newObjectId, false);
|
self(self, childId, newId, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (MetaCoreId rootId : rootIds) {
|
for (MetaCoreId rootId : rootIds) {
|
||||||
const MetaCoreGameObject* rootObject = FindGameObject(rootId);
|
MetaCoreGameObject rootObject = FindGameObject(rootId);
|
||||||
if (rootObject == nullptr) {
|
if (!rootObject) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cloneSubtree(cloneSubtree, rootId, rootObject->ParentId, true);
|
cloneSubtree(cloneSubtree, rootId, rootObject.GetParentId(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObjects_.insert(GameObjects_.end(), clonedObjects.begin(), clonedObjects.end());
|
|
||||||
return duplicatedRootIds;
|
return duplicatedRootIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds, MetaCoreId newParentId, bool keepWorldTransform) {
|
bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds, MetaCoreId newParentId, bool keepWorldTransform) {
|
||||||
if (newParentId != 0 && FindGameObject(newParentId) == nullptr) {
|
if (newParentId != 0 && !FindGameObject(newParentId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<MetaCoreId> selectedIds;
|
std::unordered_set<MetaCoreId> selectedIds;
|
||||||
for (MetaCoreId objectId : objectIds) {
|
for (MetaCoreId objectId : objectIds) {
|
||||||
if (FindGameObject(objectId) != nullptr) {
|
if (FindGameObject(objectId)) {
|
||||||
selectedIds.insert(objectId);
|
selectedIds.insert(objectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,14 +319,14 @@ bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaCoreGameObject* object = FindGameObject(objectId);
|
MetaCoreGameObject object = FindGameObject(objectId);
|
||||||
bool hasSelectedAncestor = false;
|
bool hasSelectedAncestor = false;
|
||||||
while (object != nullptr && object->ParentId != 0) {
|
while (object && object.GetParentId() != 0) {
|
||||||
if (selectedIds.contains(object->ParentId)) {
|
if (selectedIds.contains(object.GetParentId())) {
|
||||||
hasSelectedAncestor = true;
|
hasSelectedAncestor = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
object = FindGameObject(object->ParentId);
|
object = FindGameObject(object.GetParentId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSelectedAncestor) {
|
if (!hasSelectedAncestor) {
|
||||||
@ -321,17 +347,17 @@ bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds
|
|||||||
std::unordered_map<MetaCoreId, glm::mat4> worldMatrices;
|
std::unordered_map<MetaCoreId, glm::mat4> worldMatrices;
|
||||||
if (keepWorldTransform) {
|
if (keepWorldTransform) {
|
||||||
const auto buildWorldMatrix = [&](const auto& self, MetaCoreId objectId) -> glm::mat4 {
|
const auto buildWorldMatrix = [&](const auto& self, MetaCoreId objectId) -> glm::mat4 {
|
||||||
const MetaCoreGameObject* object = FindGameObject(objectId);
|
MetaCoreGameObject object = FindGameObject(objectId);
|
||||||
if (object == nullptr) {
|
if (!object) {
|
||||||
return glm::mat4(1.0F);
|
return glm::mat4(1.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::mat4 localMatrix = MetaCoreBuildTransformMatrix(object->Transform);
|
const glm::mat4 localMatrix = MetaCoreBuildTransformMatrix(object.GetComponent<MetaCoreTransformComponent>());
|
||||||
if (object->ParentId == 0) {
|
if (object.GetParentId() == 0) {
|
||||||
return localMatrix;
|
return localMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self(self, object->ParentId) * localMatrix;
|
return self(self, object.GetParentId()) * localMatrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (MetaCoreId rootId : rootIds) {
|
for (MetaCoreId rootId : rootIds) {
|
||||||
@ -344,9 +370,9 @@ bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (MetaCoreId rootId : rootIds) {
|
for (MetaCoreId rootId : rootIds) {
|
||||||
MetaCoreGameObject* object = FindGameObject(rootId);
|
MetaCoreGameObject object = FindGameObject(rootId);
|
||||||
if (object != nullptr) {
|
if (object) {
|
||||||
object->ParentId = newParentId;
|
object.SetParentId(newParentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,8 +382,8 @@ bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds
|
|||||||
const glm::mat4 inverseParentWorldMatrix = glm::inverse(newParentWorldMatrix);
|
const glm::mat4 inverseParentWorldMatrix = glm::inverse(newParentWorldMatrix);
|
||||||
|
|
||||||
for (MetaCoreId rootId : rootIds) {
|
for (MetaCoreId rootId : rootIds) {
|
||||||
MetaCoreGameObject* object = FindGameObject(rootId);
|
MetaCoreGameObject object = FindGameObject(rootId);
|
||||||
if (object == nullptr) {
|
if (!object) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +393,7 @@ bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds
|
|||||||
}
|
}
|
||||||
|
|
||||||
const glm::mat4 newLocalMatrix = inverseParentWorldMatrix * matrixIterator->second;
|
const glm::mat4 newLocalMatrix = inverseParentWorldMatrix * matrixIterator->second;
|
||||||
MetaCoreApplyMatrixToTransform(newLocalMatrix, object->Transform);
|
MetaCoreApplyMatrixToTransform(newLocalMatrix, object.GetComponent<MetaCoreTransformComponent>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,16 +402,47 @@ bool MetaCoreScene::ReparentGameObjects(const std::vector<MetaCoreId>& objectIds
|
|||||||
|
|
||||||
MetaCoreSceneSnapshot MetaCoreScene::CaptureSnapshot() const {
|
MetaCoreSceneSnapshot MetaCoreScene::CaptureSnapshot() const {
|
||||||
MetaCoreSceneSnapshot snapshot;
|
MetaCoreSceneSnapshot snapshot;
|
||||||
snapshot.GameObjects = GameObjects_;
|
auto objects = GetGameObjects();
|
||||||
|
snapshot.GameObjects.reserve(objects.size());
|
||||||
|
for (auto obj : objects) {
|
||||||
|
MetaCoreGameObjectData data;
|
||||||
|
data.Id = obj.GetId();
|
||||||
|
data.ParentId = obj.GetParentId();
|
||||||
|
data.Name = obj.GetName();
|
||||||
|
data.Transform = obj.GetComponent<MetaCoreTransformComponent>();
|
||||||
|
|
||||||
|
if (obj.HasComponent<MetaCoreCameraComponent>())
|
||||||
|
data.Camera = obj.GetComponent<MetaCoreCameraComponent>();
|
||||||
|
if (obj.HasComponent<MetaCoreMeshRendererComponent>())
|
||||||
|
data.MeshRenderer = obj.GetComponent<MetaCoreMeshRendererComponent>();
|
||||||
|
if (obj.HasComponent<MetaCoreLightComponent>())
|
||||||
|
data.Light = obj.GetComponent<MetaCoreLightComponent>();
|
||||||
|
if (obj.HasComponent<MetaCorePrefabInstanceMetadata>())
|
||||||
|
data.PrefabInstance = obj.GetComponent<MetaCorePrefabInstanceMetadata>();
|
||||||
|
|
||||||
|
snapshot.GameObjects.push_back(std::move(data));
|
||||||
|
}
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaCoreScene::RestoreSnapshot(const MetaCoreSceneSnapshot& snapshot) {
|
void MetaCoreScene::RestoreSnapshot(const MetaCoreSceneSnapshot& snapshot) {
|
||||||
GameObjects_ = snapshot.GameObjects;
|
Registry_.clear();
|
||||||
|
IdToEntity_.clear();
|
||||||
|
|
||||||
MetaCoreId maxId = 0;
|
MetaCoreId maxId = 0;
|
||||||
for (const MetaCoreGameObject& object : GameObjects_) {
|
for (const MetaCoreGameObjectData& data : snapshot.GameObjects) {
|
||||||
maxId = std::max(maxId, object.Id);
|
maxId = std::max(maxId, data.Id);
|
||||||
|
MetaCoreGameObject obj = CreateGameObjectWithId(data.Id, data.Name, data.ParentId);
|
||||||
|
obj.GetComponent<MetaCoreTransformComponent>() = data.Transform;
|
||||||
|
|
||||||
|
if (data.Camera.has_value())
|
||||||
|
obj.AddComponent<MetaCoreCameraComponent>(data.Camera.value());
|
||||||
|
if (data.MeshRenderer.has_value())
|
||||||
|
obj.AddComponent<MetaCoreMeshRendererComponent>(data.MeshRenderer.value());
|
||||||
|
if (data.Light.has_value())
|
||||||
|
obj.AddComponent<MetaCoreLightComponent>(data.Light.value());
|
||||||
|
if (data.PrefabInstance.has_value())
|
||||||
|
obj.AddComponent<MetaCorePrefabInstanceMetadata>(data.PrefabInstance.value());
|
||||||
}
|
}
|
||||||
MetaCoreIdGenerator::EnsureAbove(maxId);
|
MetaCoreIdGenerator::EnsureAbove(maxId);
|
||||||
}
|
}
|
||||||
@ -393,36 +450,35 @@ void MetaCoreScene::RestoreSnapshot(const MetaCoreSceneSnapshot& snapshot) {
|
|||||||
MetaCoreScene MetaCoreCreateDefaultScene() {
|
MetaCoreScene MetaCoreCreateDefaultScene() {
|
||||||
MetaCoreScene scene;
|
MetaCoreScene scene;
|
||||||
|
|
||||||
MetaCoreGameObject& mainCamera = scene.CreateGameObject("Main Camera");
|
MetaCoreGameObject mainCamera = scene.CreateGameObject("Main Camera");
|
||||||
mainCamera.Camera = MetaCoreCameraComponent{};
|
mainCamera.AddComponent<MetaCoreCameraComponent>().IsPrimary = true;
|
||||||
mainCamera.Camera->IsPrimary = true;
|
mainCamera.GetComponent<MetaCoreTransformComponent>().Position = glm::vec3(0.0F, 2.2F, 6.5F);
|
||||||
mainCamera.Transform.Position = glm::vec3(0.0F, 2.2F, 6.5F);
|
mainCamera.GetComponent<MetaCoreTransformComponent>().RotationEulerDegrees = glm::vec3(-15.0F, 0.0F, 0.0F);
|
||||||
mainCamera.Transform.RotationEulerDegrees = glm::vec3(-15.0F, 0.0F, 0.0F);
|
|
||||||
|
|
||||||
MetaCoreGameObject& directionalLight = scene.CreateGameObject("Directional Light");
|
MetaCoreGameObject directionalLight = scene.CreateGameObject("Directional Light");
|
||||||
directionalLight.Light = MetaCoreLightComponent{};
|
directionalLight.AddComponent<MetaCoreLightComponent>();
|
||||||
directionalLight.Transform.RotationEulerDegrees = glm::vec3(-45.0F, 30.0F, 0.0F);
|
directionalLight.GetComponent<MetaCoreTransformComponent>().RotationEulerDegrees = glm::vec3(-45.0F, 30.0F, 0.0F);
|
||||||
|
|
||||||
MetaCoreGameObject& cube = scene.CreateGameObject("Cube");
|
MetaCoreGameObject cube = scene.CreateGameObject("Cube");
|
||||||
cube.MeshRenderer = MetaCoreMeshRendererComponent{};
|
cube.AddComponent<MetaCoreMeshRendererComponent>();
|
||||||
cube.Transform.Position = glm::vec3(0.0F, 0.5F, 0.0F);
|
cube.GetComponent<MetaCoreTransformComponent>().Position = glm::vec3(0.0F, 0.5F, 0.0F);
|
||||||
|
|
||||||
MetaCoreGameObject& valve = scene.CreateGameObject("Valve");
|
MetaCoreGameObject valve = scene.CreateGameObject("Valve");
|
||||||
valve.MeshRenderer = MetaCoreMeshRendererComponent{};
|
auto& valveMesh = valve.AddComponent<MetaCoreMeshRendererComponent>();
|
||||||
valve.Transform.Position = glm::vec3(-2.2F, 0.5F, 0.0F);
|
valve.GetComponent<MetaCoreTransformComponent>().Position = glm::vec3(-2.2F, 0.5F, 0.0F);
|
||||||
valve.MeshRenderer->BaseColor = glm::vec3(0.85F, 0.45F, 0.20F);
|
valveMesh.BaseColor = glm::vec3(0.85F, 0.45F, 0.20F);
|
||||||
|
|
||||||
MetaCoreGameObject& tank = scene.CreateGameObject("Tank");
|
MetaCoreGameObject tank = scene.CreateGameObject("Tank");
|
||||||
tank.MeshRenderer = MetaCoreMeshRendererComponent{};
|
auto& tankMesh = tank.AddComponent<MetaCoreMeshRendererComponent>();
|
||||||
tank.Transform.Position = glm::vec3(2.2F, 0.5F, 0.0F);
|
tank.GetComponent<MetaCoreTransformComponent>().Position = glm::vec3(2.2F, 0.5F, 0.0F);
|
||||||
tank.Transform.Scale = glm::vec3(1.4F, 1.4F, 1.4F);
|
tank.GetComponent<MetaCoreTransformComponent>().Scale = glm::vec3(1.4F, 1.4F, 1.4F);
|
||||||
tank.MeshRenderer->BaseColor = glm::vec3(0.35F, 0.65F, 0.90F);
|
tankMesh.BaseColor = glm::vec3(0.35F, 0.65F, 0.90F);
|
||||||
|
|
||||||
MetaCoreGameObject& alarmBeacon = scene.CreateGameObject("Alarm Beacon");
|
MetaCoreGameObject alarmBeacon = scene.CreateGameObject("Alarm Beacon");
|
||||||
alarmBeacon.Light = MetaCoreLightComponent{};
|
auto& beaconLight = alarmBeacon.AddComponent<MetaCoreLightComponent>();
|
||||||
alarmBeacon.Light->Intensity = 0.0F;
|
beaconLight.Intensity = 0.0F;
|
||||||
alarmBeacon.Light->Color = glm::vec3(1.0F, 0.15F, 0.1F);
|
beaconLight.Color = glm::vec3(1.0F, 0.15F, 0.1F);
|
||||||
alarmBeacon.Transform.Position = glm::vec3(0.0F, 2.5F, 0.0F);
|
alarmBeacon.GetComponent<MetaCoreTransformComponent>().Position = glm::vec3(0.0F, 2.5F, 0.0F);
|
||||||
|
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <glm/vec3.hpp>
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -12,7 +13,6 @@
|
|||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
MC_ENUM()
|
MC_ENUM()
|
||||||
// 定义第一阶段内置的网格类型。
|
|
||||||
enum class MetaCoreBuiltinMeshType {
|
enum class MetaCoreBuiltinMeshType {
|
||||||
Cube
|
Cube
|
||||||
};
|
};
|
||||||
@ -31,7 +31,6 @@ enum class MetaCoreMeshAlphaMode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
// 表示 Unity 风格对象的变换组件。
|
|
||||||
struct MetaCoreTransformComponent {
|
struct MetaCoreTransformComponent {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
@ -44,7 +43,6 @@ struct MetaCoreTransformComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
// 表示场景中用于观察的摄像机组件。
|
|
||||||
struct MetaCoreCameraComponent {
|
struct MetaCoreCameraComponent {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
@ -59,7 +57,6 @@ struct MetaCoreCameraComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
// 表示一个最小可用的网格渲染组件。
|
|
||||||
struct MetaCoreMeshRendererComponent {
|
struct MetaCoreMeshRendererComponent {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
@ -72,8 +69,22 @@ struct MetaCoreMeshRendererComponent {
|
|||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::vector<MetaCoreAssetGuid> MaterialAssetGuids{};
|
std::vector<MetaCoreAssetGuid> MaterialAssetGuids{};
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
|
MetaCoreAssetGuid SourceModelAssetGuid{};
|
||||||
|
MC_PROPERTY()
|
||||||
std::string SourceModelPath{};
|
std::string SourceModelPath{};
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
|
std::string SourceNodePath{};
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreAssetGuid BaseColorTextureGuid{};
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreAssetGuid MetallicRoughnessTextureGuid{};
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreAssetGuid NormalTextureGuid{};
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreAssetGuid EmissiveTextureGuid{};
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreAssetGuid AoTextureGuid{};
|
||||||
|
MC_PROPERTY()
|
||||||
std::string BaseColorTexturePath{};
|
std::string BaseColorTexturePath{};
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::string MetallicRoughnessTexturePath{};
|
std::string MetallicRoughnessTexturePath{};
|
||||||
@ -107,7 +118,6 @@ struct MetaCoreMeshRendererComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
// 表示第一阶段场景中的方向光组件。
|
|
||||||
struct MetaCoreLightComponent {
|
struct MetaCoreLightComponent {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
|
||||||
#include "MetaCoreFoundation/MetaCoreAssetGuid.h"
|
#include "MetaCoreFoundation/MetaCoreAssetGuid.h"
|
||||||
|
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||||
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
||||||
#include "MetaCoreScene/MetaCoreComponents.h"
|
#include "MetaCoreScene/MetaCoreComponents.h"
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
|
class MetaCoreScene;
|
||||||
|
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
struct MetaCorePrefabInstanceMetadata {
|
struct MetaCorePrefabInstanceMetadata {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
@ -24,9 +27,88 @@ struct MetaCorePrefabInstanceMetadata {
|
|||||||
MetaCoreId PrefabInstanceRootId = 0;
|
MetaCoreId PrefabInstanceRootId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Component structs for basic properties
|
||||||
MC_STRUCT()
|
MC_STRUCT()
|
||||||
// 表示一个 Unity 风格的场景对象。
|
struct MetaCoreIdComponent {
|
||||||
struct MetaCoreGameObject {
|
MC_GENERATED_BODY()
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreId Id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_STRUCT()
|
||||||
|
struct MetaCoreHierarchyComponent {
|
||||||
|
MC_GENERATED_BODY()
|
||||||
|
MC_PROPERTY()
|
||||||
|
MetaCoreId ParentId = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
MC_STRUCT()
|
||||||
|
struct MetaCoreNameComponent {
|
||||||
|
MC_GENERATED_BODY()
|
||||||
|
MC_PROPERTY()
|
||||||
|
std::string Name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The ECS handle
|
||||||
|
class MetaCoreGameObject {
|
||||||
|
public:
|
||||||
|
MetaCoreGameObject() = default;
|
||||||
|
MetaCoreGameObject(entt::entity handle, MetaCoreScene* scene)
|
||||||
|
: EntityHandle(handle), Scene(scene) {}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
T& AddComponent(Args&&... args) {
|
||||||
|
// Implementation will be in MetaCoreScene.h due to circular dependency
|
||||||
|
return InternalAddComponent<T>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T& GetComponent() {
|
||||||
|
return InternalGetComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& GetComponent() const {
|
||||||
|
return InternalGetComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool HasComponent() const {
|
||||||
|
return InternalHasComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void RemoveComponent() {
|
||||||
|
InternalRemoveComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const { return EntityHandle != entt::null && Scene != nullptr; }
|
||||||
|
bool operator==(const MetaCoreGameObject& other) const { return EntityHandle == other.EntityHandle && Scene == other.Scene; }
|
||||||
|
bool operator!=(const MetaCoreGameObject& other) const { return !(*this == other); }
|
||||||
|
|
||||||
|
entt::entity GetEntityHandle() const { return EntityHandle; }
|
||||||
|
MetaCoreScene* GetScene() const { return Scene; }
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
MetaCoreId GetId() const;
|
||||||
|
MetaCoreId GetParentId() const;
|
||||||
|
void SetParentId(MetaCoreId id);
|
||||||
|
std::string& GetName();
|
||||||
|
const std::string& GetName() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T, typename... Args> T& InternalAddComponent(Args&&... args);
|
||||||
|
template<typename T> T& InternalGetComponent() const;
|
||||||
|
template<typename T> bool InternalHasComponent() const;
|
||||||
|
template<typename T> void InternalRemoveComponent();
|
||||||
|
|
||||||
|
entt::entity EntityHandle{entt::null};
|
||||||
|
MetaCoreScene* Scene = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Old struct retained for serialization/snapshot MVP
|
||||||
|
MC_STRUCT()
|
||||||
|
struct MetaCoreGameObjectData {
|
||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
||||||
#include "MetaCoreScene/MetaCoreSceneDocument.h"
|
|
||||||
#include "MetaCoreScene/MetaCoreGameObject.h"
|
#include "MetaCoreScene/MetaCoreGameObject.h"
|
||||||
|
#include "MetaCoreScene/MetaCoreSceneDocument.h"
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace MetaCore {
|
namespace MetaCore {
|
||||||
|
|
||||||
@ -13,61 +15,85 @@ struct MetaCoreSceneSnapshot {
|
|||||||
MC_GENERATED_BODY()
|
MC_GENERATED_BODY()
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::vector<MetaCoreGameObject> GameObjects;
|
std::vector<MetaCoreGameObjectData> GameObjects;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 负责存储和查询场景中的全部对象。
|
|
||||||
class MetaCoreScene {
|
class MetaCoreScene {
|
||||||
public:
|
public:
|
||||||
// 创建一个新的场景对象。
|
MetaCoreGameObject CreateGameObject(const std::string& name, MetaCoreId parentId = 0);
|
||||||
MetaCoreGameObject& CreateGameObject(const std::string& name, MetaCoreId parentId = 0);
|
MetaCoreGameObject CreateGameObjectWithId(MetaCoreId id, const std::string& name, MetaCoreId parentId = 0);
|
||||||
|
|
||||||
// 通过标识查找场景对象。
|
[[nodiscard]] MetaCoreGameObject FindGameObject(MetaCoreId objectId);
|
||||||
[[nodiscard]] MetaCoreGameObject* FindGameObject(MetaCoreId objectId);
|
[[nodiscard]] MetaCoreGameObject FindGameObject(MetaCoreId objectId) const;
|
||||||
[[nodiscard]] const MetaCoreGameObject* FindGameObject(MetaCoreId objectId) const;
|
|
||||||
|
|
||||||
// 返回全部对象。
|
[[nodiscard]] std::vector<MetaCoreGameObject> GetGameObjects();
|
||||||
[[nodiscard]] std::vector<MetaCoreGameObject>& GetGameObjects();
|
[[nodiscard]] std::vector<MetaCoreGameObject> GetGameObjects() const;
|
||||||
[[nodiscard]] const std::vector<MetaCoreGameObject>& GetGameObjects() const;
|
|
||||||
|
|
||||||
// 返回根节点对象列表。
|
|
||||||
[[nodiscard]] std::vector<MetaCoreId> GetRootObjectIds() const;
|
[[nodiscard]] std::vector<MetaCoreId> GetRootObjectIds() const;
|
||||||
|
|
||||||
// 返回某个对象的直接子对象列表。
|
|
||||||
[[nodiscard]] std::vector<MetaCoreId> GetChildrenOf(MetaCoreId parentId) const;
|
[[nodiscard]] std::vector<MetaCoreId> GetChildrenOf(MetaCoreId parentId) const;
|
||||||
|
|
||||||
// 按层级前序遍历顺序返回对象标识列表。
|
|
||||||
[[nodiscard]] std::vector<MetaCoreId> BuildHierarchyPreorder() const;
|
[[nodiscard]] std::vector<MetaCoreId> BuildHierarchyPreorder() const;
|
||||||
|
|
||||||
// 返回指定根对象的完整子树标识(含自身)。
|
|
||||||
[[nodiscard]] std::vector<MetaCoreId> GetSubtreeObjectIds(MetaCoreId rootId) const;
|
[[nodiscard]] std::vector<MetaCoreId> GetSubtreeObjectIds(MetaCoreId rootId) const;
|
||||||
|
|
||||||
// 判断对象是否是另一个对象的后代。
|
|
||||||
[[nodiscard]] bool IsDescendantOf(MetaCoreId objectId, MetaCoreId ancestorId) const;
|
[[nodiscard]] bool IsDescendantOf(MetaCoreId objectId, MetaCoreId ancestorId) const;
|
||||||
|
|
||||||
// 重命名对象。
|
|
||||||
bool RenameGameObject(MetaCoreId objectId, const std::string& name);
|
bool RenameGameObject(MetaCoreId objectId, const std::string& name);
|
||||||
|
|
||||||
// 删除对象(包含其子树)。返回实际删除的全部对象标识。
|
|
||||||
[[nodiscard]] std::vector<MetaCoreId> DeleteGameObjects(const std::vector<MetaCoreId>& objectIds);
|
[[nodiscard]] std::vector<MetaCoreId> DeleteGameObjects(const std::vector<MetaCoreId>& objectIds);
|
||||||
|
|
||||||
// 复制对象(包含其子树)。返回复制后顶层对象标识。
|
|
||||||
[[nodiscard]] std::vector<MetaCoreId> DuplicateGameObjects(const std::vector<MetaCoreId>& objectIds);
|
[[nodiscard]] std::vector<MetaCoreId> DuplicateGameObjects(const std::vector<MetaCoreId>& objectIds);
|
||||||
|
|
||||||
// 批量重挂接对象到新父节点。
|
|
||||||
bool ReparentGameObjects(const std::vector<MetaCoreId>& objectIds, MetaCoreId newParentId, bool keepWorldTransform);
|
bool ReparentGameObjects(const std::vector<MetaCoreId>& objectIds, MetaCoreId newParentId, bool keepWorldTransform);
|
||||||
|
|
||||||
// 场景快照捕获与恢复。
|
|
||||||
[[nodiscard]] MetaCoreSceneSnapshot CaptureSnapshot() const;
|
[[nodiscard]] MetaCoreSceneSnapshot CaptureSnapshot() const;
|
||||||
void RestoreSnapshot(const MetaCoreSceneSnapshot& snapshot);
|
void RestoreSnapshot(const MetaCoreSceneSnapshot& snapshot);
|
||||||
|
|
||||||
|
entt::registry& GetRegistry() { return Registry_; }
|
||||||
|
const entt::registry& GetRegistry() const { return Registry_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CollectPreorder(MetaCoreId objectId, std::vector<MetaCoreId>& output) const;
|
void CollectPreorder(MetaCoreId objectId, std::vector<MetaCoreId>& output) const;
|
||||||
|
|
||||||
std::vector<MetaCoreGameObject> GameObjects_{};
|
entt::registry Registry_;
|
||||||
|
std::unordered_map<MetaCoreId, entt::entity> IdToEntity_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建一个包含默认相机、灯光和立方体的启动场景。
|
|
||||||
MetaCoreScene MetaCoreCreateDefaultScene();
|
MetaCoreScene MetaCoreCreateDefaultScene();
|
||||||
|
|
||||||
|
// MetaCoreGameObject inline implementations
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
T& MetaCoreGameObject::InternalAddComponent(Args&&... args) {
|
||||||
|
return Scene->GetRegistry().emplace<T>(EntityHandle, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T& MetaCoreGameObject::InternalGetComponent() const {
|
||||||
|
return Scene->GetRegistry().get<T>(EntityHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool MetaCoreGameObject::InternalHasComponent() const {
|
||||||
|
return Scene->GetRegistry().any_of<T>(EntityHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void MetaCoreGameObject::InternalRemoveComponent() {
|
||||||
|
Scene->GetRegistry().remove<T>(EntityHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MetaCoreId MetaCoreGameObject::GetId() const {
|
||||||
|
return GetComponent<MetaCoreIdComponent>().Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MetaCoreId MetaCoreGameObject::GetParentId() const {
|
||||||
|
return GetComponent<MetaCoreHierarchyComponent>().ParentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MetaCoreGameObject::SetParentId(MetaCoreId id) {
|
||||||
|
GetComponent<MetaCoreHierarchyComponent>().ParentId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string& MetaCoreGameObject::GetName() {
|
||||||
|
return GetComponent<MetaCoreNameComponent>().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const std::string& MetaCoreGameObject::GetName() const {
|
||||||
|
return GetComponent<MetaCoreNameComponent>().Name;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MetaCore
|
} // namespace MetaCore
|
||||||
|
|||||||
@ -31,7 +31,7 @@ struct MetaCoreSceneDocument {
|
|||||||
std::string Name{};
|
std::string Name{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
std::vector<MetaCoreGameObject> GameObjects{};
|
std::vector<MetaCoreGameObjectData> GameObjects{};
|
||||||
|
|
||||||
MC_PROPERTY()
|
MC_PROPERTY()
|
||||||
MetaCoreEditorSelectionSnapshot Selection{};
|
MetaCoreEditorSelectionSnapshot Selection{};
|
||||||
|
|||||||
BIN
build_out.txt
BIN
build_out.txt
Binary file not shown.
@ -193,7 +193,7 @@ void MetaCoreTestScenePackageProjectStartupLoad() {
|
|||||||
MetaCore::MetaCoreSceneDocument sceneDocument;
|
MetaCore::MetaCoreSceneDocument sceneDocument;
|
||||||
sceneDocument.Name = "Main";
|
sceneDocument.Name = "Main";
|
||||||
const MetaCore::MetaCoreScene sourceScene = MetaCore::MetaCoreCreateDefaultScene();
|
const MetaCore::MetaCoreScene sourceScene = MetaCore::MetaCoreCreateDefaultScene();
|
||||||
sceneDocument.GameObjects = sourceScene.GetGameObjects();
|
sceneDocument.GameObjects = sourceScene.CaptureSnapshot().GameObjects;
|
||||||
|
|
||||||
const std::filesystem::path scenePath = tempProjectRoot / "Scenes" / "Main.mcscene";
|
const std::filesystem::path scenePath = tempProjectRoot / "Scenes" / "Main.mcscene";
|
||||||
MetaCoreExpect(MetaCore::MetaCoreWriteScenePackage(scenePath, sceneDocument), "应能写入二进制场景包");
|
MetaCoreExpect(MetaCore::MetaCoreWriteScenePackage(scenePath, sceneDocument), "应能写入二进制场景包");
|
||||||
@ -334,7 +334,7 @@ void MetaCoreTestAssetDatabaseRenamePathUpdatesProjectDescriptor() {
|
|||||||
|
|
||||||
MetaCore::MetaCoreSceneDocument sceneDocument;
|
MetaCore::MetaCoreSceneDocument sceneDocument;
|
||||||
sceneDocument.Name = "Main";
|
sceneDocument.Name = "Main";
|
||||||
sceneDocument.GameObjects = MetaCore::MetaCoreCreateDefaultScene().GetGameObjects();
|
sceneDocument.GameObjects = MetaCore::MetaCoreCreateDefaultScene().CaptureSnapshot().GameObjects;
|
||||||
MetaCoreExpect(
|
MetaCoreExpect(
|
||||||
MetaCore::MetaCoreWriteScenePackage(tempProjectRoot / "Scenes" / "Main.mcscene", sceneDocument),
|
MetaCore::MetaCoreWriteScenePackage(tempProjectRoot / "Scenes" / "Main.mcscene", sceneDocument),
|
||||||
"应能写入场景包"
|
"应能写入场景包"
|
||||||
@ -396,7 +396,7 @@ void MetaCoreTestAssetDatabaseMovePathUpdatesProjectDescriptor() {
|
|||||||
|
|
||||||
MetaCore::MetaCoreSceneDocument sceneDocument;
|
MetaCore::MetaCoreSceneDocument sceneDocument;
|
||||||
sceneDocument.Name = "Main";
|
sceneDocument.Name = "Main";
|
||||||
sceneDocument.GameObjects = MetaCore::MetaCoreCreateDefaultScene().GetGameObjects();
|
sceneDocument.GameObjects = MetaCore::MetaCoreCreateDefaultScene().CaptureSnapshot().GameObjects;
|
||||||
MetaCoreExpect(
|
MetaCoreExpect(
|
||||||
MetaCore::MetaCoreWriteScenePackage(tempProjectRoot / "Scenes" / "Main.mcscene", sceneDocument),
|
MetaCore::MetaCoreWriteScenePackage(tempProjectRoot / "Scenes" / "Main.mcscene", sceneDocument),
|
||||||
"应能写入场景包"
|
"应能写入场景包"
|
||||||
@ -567,6 +567,7 @@ void MetaCoreTestImportPipelineAndCook() {
|
|||||||
std::filesystem::temp_directory_path() / "MetaCoreImportCookProject";
|
std::filesystem::temp_directory_path() / "MetaCoreImportCookProject";
|
||||||
std::filesystem::remove_all(tempProjectRoot);
|
std::filesystem::remove_all(tempProjectRoot);
|
||||||
std::filesystem::create_directories(tempProjectRoot / "Assets");
|
std::filesystem::create_directories(tempProjectRoot / "Assets");
|
||||||
|
std::filesystem::create_directories(tempProjectRoot / "Assets" / "Textures");
|
||||||
std::filesystem::create_directories(tempProjectRoot / "Scenes");
|
std::filesystem::create_directories(tempProjectRoot / "Scenes");
|
||||||
std::filesystem::create_directories(tempProjectRoot / "Library");
|
std::filesystem::create_directories(tempProjectRoot / "Library");
|
||||||
|
|
||||||
@ -631,6 +632,7 @@ void MetaCoreTestProjectDescriptorAndGltfImporterSkeleton() {
|
|||||||
std::filesystem::temp_directory_path() / "MetaCoreProjectGltfImporterProject";
|
std::filesystem::temp_directory_path() / "MetaCoreProjectGltfImporterProject";
|
||||||
std::filesystem::remove_all(tempProjectRoot);
|
std::filesystem::remove_all(tempProjectRoot);
|
||||||
std::filesystem::create_directories(tempProjectRoot / "Assets");
|
std::filesystem::create_directories(tempProjectRoot / "Assets");
|
||||||
|
std::filesystem::create_directories(tempProjectRoot / "Assets" / "Textures");
|
||||||
std::filesystem::create_directories(tempProjectRoot / "Scenes");
|
std::filesystem::create_directories(tempProjectRoot / "Scenes");
|
||||||
std::filesystem::create_directories(tempProjectRoot / "ConfigRuntime");
|
std::filesystem::create_directories(tempProjectRoot / "ConfigRuntime");
|
||||||
std::filesystem::create_directories(tempProjectRoot / "UiDocuments");
|
std::filesystem::create_directories(tempProjectRoot / "UiDocuments");
|
||||||
@ -649,6 +651,15 @@ void MetaCoreTestProjectDescriptorAndGltfImporterSkeleton() {
|
|||||||
<< "}\n";
|
<< "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const unsigned char valveTextureData[] = {
|
||||||
|
0x50, 0x36, 0x0A, 0x31, 0x20, 0x31, 0x0A, 0x32,
|
||||||
|
0x35, 0x35, 0x0A, 0xFF, 0x80, 0x40
|
||||||
|
};
|
||||||
|
std::ofstream textureFile(tempProjectRoot / "Assets" / "Textures" / "ValveBaseColor.ppm", std::ios::binary | std::ios::trunc);
|
||||||
|
textureFile.write(reinterpret_cast<const char*>(valveTextureData), sizeof(valveTextureData));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::ofstream gltfFile(tempProjectRoot / "Assets" / "Valve.gltf", std::ios::trunc);
|
std::ofstream gltfFile(tempProjectRoot / "Assets" / "Valve.gltf", std::ios::trunc);
|
||||||
gltfFile
|
gltfFile
|
||||||
@ -659,7 +670,23 @@ void MetaCoreTestProjectDescriptorAndGltfImporterSkeleton() {
|
|||||||
<< " \"meshes\": [{\"name\": \"ValveMesh\", \"primitives\": [{\"material\": 0}]}],\n"
|
<< " \"meshes\": [{\"name\": \"ValveMesh\", \"primitives\": [{\"material\": 0}]}],\n"
|
||||||
<< " \"materials\": [{\"name\": \"ValveMaterial\", \"pbrMetallicRoughness\": {\"baseColorTexture\": {\"index\": 0}}}],\n"
|
<< " \"materials\": [{\"name\": \"ValveMaterial\", \"pbrMetallicRoughness\": {\"baseColorTexture\": {\"index\": 0}}}],\n"
|
||||||
<< " \"textures\": [{\"source\": 0}],\n"
|
<< " \"textures\": [{\"source\": 0}],\n"
|
||||||
<< " \"images\": [{\"uri\": \"Textures/ValveBaseColor.png\"}]\n"
|
<< " \"images\": [{\"uri\": \"Textures/ValveBaseColor.ppm\"}]\n"
|
||||||
|
<< "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream gltfFile(tempProjectRoot / "Assets" / "EmbeddedTexture.gltf", std::ios::trunc);
|
||||||
|
gltfFile
|
||||||
|
<< "{\n"
|
||||||
|
<< " \"asset\": {\"version\": \"2.0\"},\n"
|
||||||
|
<< " \"scenes\": [{\"nodes\": [0]}],\n"
|
||||||
|
<< " \"nodes\": [{\"mesh\": 0, \"name\": \"EmbeddedTextureNode\"}],\n"
|
||||||
|
<< " \"meshes\": [{\"name\": \"EmbeddedTextureMesh\", \"primitives\": [{\"material\": 0}]}],\n"
|
||||||
|
<< " \"materials\": [{\"name\": \"EmbeddedTextureMaterial\", \"pbrMetallicRoughness\": {\"baseColorTexture\": {\"index\": 0}}}],\n"
|
||||||
|
<< " \"textures\": [{\"source\": 0}],\n"
|
||||||
|
<< " \"images\": [{\"bufferView\": 0, \"mimeType\": \"image/x-portable-pixmap\", \"name\": \"EmbeddedBaseColor\"}],\n"
|
||||||
|
<< " \"bufferViews\": [{\"buffer\": 0, \"byteOffset\": 0, \"byteLength\": 14}],\n"
|
||||||
|
<< " \"buffers\": [{\"byteLength\": 14, \"uri\": \"data:application/octet-stream;base64,UDYKMSAxCjI1NQr/gEA=\"}]\n"
|
||||||
<< "}\n";
|
<< "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,9 +714,11 @@ void MetaCoreTestProjectDescriptorAndGltfImporterSkeleton() {
|
|||||||
const auto assetDatabase = moduleRegistry.ResolveService<MetaCore::MetaCoreIAssetDatabaseService>();
|
const auto assetDatabase = moduleRegistry.ResolveService<MetaCore::MetaCoreIAssetDatabaseService>();
|
||||||
const auto packageService = moduleRegistry.ResolveService<MetaCore::MetaCoreIPackageService>();
|
const auto packageService = moduleRegistry.ResolveService<MetaCore::MetaCoreIPackageService>();
|
||||||
const auto reflectionRegistry = moduleRegistry.ResolveService<MetaCore::MetaCoreIReflectionRegistry>();
|
const auto reflectionRegistry = moduleRegistry.ResolveService<MetaCore::MetaCoreIReflectionRegistry>();
|
||||||
|
const auto assetEditingService = moduleRegistry.ResolveService<MetaCore::MetaCoreIAssetEditingService>();
|
||||||
MetaCoreExpect(assetDatabase != nullptr, "应解析到 AssetDatabaseService");
|
MetaCoreExpect(assetDatabase != nullptr, "应解析到 AssetDatabaseService");
|
||||||
MetaCoreExpect(packageService != nullptr, "应解析到 PackageService");
|
MetaCoreExpect(packageService != nullptr, "应解析到 PackageService");
|
||||||
MetaCoreExpect(reflectionRegistry != nullptr, "应解析到 ReflectionRegistry");
|
MetaCoreExpect(reflectionRegistry != nullptr, "应解析到 ReflectionRegistry");
|
||||||
|
MetaCoreExpect(assetEditingService != nullptr, "应解析到 AssetEditingService");
|
||||||
|
|
||||||
const auto& project = assetDatabase->GetProjectDescriptor();
|
const auto& project = assetDatabase->GetProjectDescriptor();
|
||||||
MetaCoreExpect(project.RuntimePath.filename() == "ConfigRuntime", "项目应读取 runtime_directory");
|
MetaCoreExpect(project.RuntimePath.filename() == "ConfigRuntime", "项目应读取 runtime_directory");
|
||||||
@ -725,7 +754,7 @@ void MetaCoreTestProjectDescriptorAndGltfImporterSkeleton() {
|
|||||||
MetaCoreExpect(gltfDocument.Meshes.front().PrimitiveCount == 1, "glTF mesh 骨架应写入 primitive 数");
|
MetaCoreExpect(gltfDocument.Meshes.front().PrimitiveCount == 1, "glTF mesh 骨架应写入 primitive 数");
|
||||||
MetaCoreExpect(!gltfDocument.Materials.empty() && gltfDocument.Materials.front().Name == "ValveMaterial", "glTF 导入文档应提取材质名称");
|
MetaCoreExpect(!gltfDocument.Materials.empty() && gltfDocument.Materials.front().Name == "ValveMaterial", "glTF 导入文档应提取材质名称");
|
||||||
MetaCoreExpect(!gltfDocument.Textures.empty(), "glTF 导入文档应记录引用贴图");
|
MetaCoreExpect(!gltfDocument.Textures.empty(), "glTF 导入文档应记录引用贴图");
|
||||||
MetaCoreExpect(gltfDocument.Textures.front().SourcePath == std::filesystem::path("Textures") / "ValveBaseColor.png", "glTF 导入文档应保存贴图路径");
|
MetaCoreExpect(gltfDocument.Textures.front().SourcePath == std::filesystem::path("Textures") / "ValveBaseColor.ppm", "glTF 导入文档应保存贴图路径");
|
||||||
MetaCoreExpect(gltfDocument.GeneratedMeshAssets.size() == gltfDocument.Meshes.size(), "glTF 导入文档应生成 mesh 资源骨架");
|
MetaCoreExpect(gltfDocument.GeneratedMeshAssets.size() == gltfDocument.Meshes.size(), "glTF 导入文档应生成 mesh 资源骨架");
|
||||||
MetaCoreExpect(gltfDocument.GeneratedMaterialAssets.size() == gltfDocument.Materials.size(), "glTF 导入文档应生成材质资源骨架");
|
MetaCoreExpect(gltfDocument.GeneratedMaterialAssets.size() == gltfDocument.Materials.size(), "glTF 导入文档应生成材质资源骨架");
|
||||||
MetaCoreExpect(gltfDocument.GeneratedTextureAssets.size() == gltfDocument.Textures.size(), "glTF 导入文档应生成纹理资源骨架");
|
MetaCoreExpect(gltfDocument.GeneratedTextureAssets.size() == gltfDocument.Textures.size(), "glTF 导入文档应生成纹理资源骨架");
|
||||||
@ -733,6 +762,39 @@ void MetaCoreTestProjectDescriptorAndGltfImporterSkeleton() {
|
|||||||
MetaCoreExpect(gltfDocument.GeneratedMaterialAssets.front().AssetGuid.IsValid(), "生成的材质资源应有 GUID");
|
MetaCoreExpect(gltfDocument.GeneratedMaterialAssets.front().AssetGuid.IsValid(), "生成的材质资源应有 GUID");
|
||||||
MetaCoreExpect(gltfDocument.GeneratedTextureAssets.front().AssetGuid.IsValid(), "生成的纹理资源应有 GUID");
|
MetaCoreExpect(gltfDocument.GeneratedTextureAssets.front().AssetGuid.IsValid(), "生成的纹理资源应有 GUID");
|
||||||
MetaCoreExpect(gltfDocument.GeneratedMaterialAssets.front().BaseColorTexture.IsValid(), "材质资源应引用生成的贴图资源");
|
MetaCoreExpect(gltfDocument.GeneratedMaterialAssets.front().BaseColorTexture.IsValid(), "材质资源应引用生成的贴图资源");
|
||||||
|
const std::filesystem::path gltfGeneratedTextureRuntimePath =
|
||||||
|
tempProjectRoot / "Library" / "RuntimeAssets" / "Textures" /
|
||||||
|
(gltfDocument.GeneratedTextureAssets.front().AssetGuid.ToString() + ".mcasset");
|
||||||
|
MetaCoreExpect(std::filesystem::exists(gltfGeneratedTextureRuntimePath), "glTF generated texture should write a runtime texture package");
|
||||||
|
const auto gltfGeneratedTextureDocument =
|
||||||
|
assetEditingService->LoadTextureAsset(gltfDocument.GeneratedTextureAssets.front().AssetGuid);
|
||||||
|
MetaCoreExpect(gltfGeneratedTextureDocument.has_value(), "AssetEditingService 应能读取外部贴图 runtime 资源");
|
||||||
|
MetaCoreExpect(gltfGeneratedTextureDocument->Width == 1 && gltfGeneratedTextureDocument->Height == 1, "外部贴图 runtime 资源应带有真实尺寸");
|
||||||
|
|
||||||
|
const auto embeddedTextureRecord =
|
||||||
|
assetDatabase->FindAssetByRelativePath(std::filesystem::path("Assets") / "EmbeddedTexture.gltf");
|
||||||
|
MetaCoreExpect(embeddedTextureRecord.has_value(), "应能找到内嵌贴图 glTF 资源记录");
|
||||||
|
const auto embeddedTexturePackage = packageService->ReadPackage(tempProjectRoot / embeddedTextureRecord->PackagePath);
|
||||||
|
MetaCoreExpect(embeddedTexturePackage.has_value(), "内嵌贴图 glTF 应生成包文件");
|
||||||
|
MetaCore::MetaCoreModelAssetDocument embeddedTextureDocument;
|
||||||
|
MetaCoreExpect(
|
||||||
|
!embeddedTexturePackage->PayloadSections.empty() &&
|
||||||
|
MetaCore::MetaCoreDeserializeFromBytes(
|
||||||
|
embeddedTexturePackage->PayloadSections.front(),
|
||||||
|
embeddedTextureDocument,
|
||||||
|
reflectionRegistry->GetTypeRegistry()
|
||||||
|
),
|
||||||
|
"内嵌贴图 glTF 包应能反序列化为模型资产"
|
||||||
|
);
|
||||||
|
MetaCoreExpect(!embeddedTextureDocument.GeneratedTextureAssets.empty(), "内嵌贴图 glTF 应生成纹理子资源");
|
||||||
|
const std::filesystem::path embeddedTextureRuntimePath =
|
||||||
|
tempProjectRoot / "Library" / "RuntimeAssets" / "Textures" /
|
||||||
|
(embeddedTextureDocument.GeneratedTextureAssets.front().AssetGuid.ToString() + ".mcasset");
|
||||||
|
MetaCoreExpect(std::filesystem::exists(embeddedTextureRuntimePath), "内嵌 bufferView 贴图应生成 runtime 纹理包");
|
||||||
|
const auto embeddedRuntimeTextureDocument =
|
||||||
|
assetEditingService->LoadTextureAsset(embeddedTextureDocument.GeneratedTextureAssets.front().AssetGuid);
|
||||||
|
MetaCoreExpect(embeddedRuntimeTextureDocument.has_value(), "AssetEditingService 应能读取内嵌贴图 runtime 资源");
|
||||||
|
MetaCoreExpect(embeddedRuntimeTextureDocument->Width == 1 && embeddedRuntimeTextureDocument->Height == 1, "内嵌贴图 runtime 资源应带有真实尺寸");
|
||||||
|
|
||||||
const auto glbRecord = assetDatabase->FindAssetByRelativePath(std::filesystem::path("Assets") / "Tank.glb");
|
const auto glbRecord = assetDatabase->FindAssetByRelativePath(std::filesystem::path("Assets") / "Tank.glb");
|
||||||
MetaCoreExpect(glbRecord.has_value(), "应能找到 glb 资源记录");
|
MetaCoreExpect(glbRecord.has_value(), "应能找到 glb 资源记录");
|
||||||
@ -882,20 +944,25 @@ void MetaCoreTestInstantiateImportedModelAssetIntoScene() {
|
|||||||
|
|
||||||
const MetaCore::MetaCoreGameObject* instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
const MetaCore::MetaCoreGameObject* instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
||||||
MetaCoreExpect(instantiatedRoot != nullptr, "实例化后应能找到根对象");
|
MetaCoreExpect(instantiatedRoot != nullptr, "实例化后应能找到根对象");
|
||||||
MetaCoreExpect(instantiatedRoot->Name == "Pump", "实例化根对象名称应来自导入节点");
|
MetaCoreExpect(instantiatedRoot->Name == "Pump.gltf", "model root should use source file name");
|
||||||
MetaCoreExpect(instantiatedRoot->MeshRenderer.has_value(), "导入模型实例应带 MeshRenderer");
|
const std::vector<MetaCore::MetaCoreId> instantiatedChildren = scene.GetChildrenOf(*instantiatedRootId);
|
||||||
MetaCoreExpect(instantiatedRoot->MeshRenderer->MeshSource == MetaCore::MetaCoreMeshSourceKind::Asset, "导入模型实例应使用 Asset MeshSource");
|
MetaCoreExpect(instantiatedChildren.size() == 1, "model root should contain imported node");
|
||||||
MetaCoreExpect(instantiatedRoot->MeshRenderer->MeshAssetGuid.IsValid(), "导入模型实例应绑定 MeshAssetGuid");
|
const MetaCore::MetaCoreGameObject* instantiatedRenderable = scene.FindGameObject(instantiatedChildren.front());
|
||||||
MetaCoreExpect(!instantiatedRoot->MeshRenderer->MaterialAssetGuids.empty(), "导入模型实例应绑定材质资源");
|
MetaCoreExpect(instantiatedRenderable != nullptr, "instantiated renderable node should exist");
|
||||||
|
MetaCoreExpect(instantiatedRenderable->Name == "Pump", "renderable child name should come from imported node");
|
||||||
|
MetaCoreExpect(instantiatedRenderable->MeshRenderer.has_value(), "renderable node should have MeshRenderer");
|
||||||
|
MetaCoreExpect(instantiatedRenderable->MeshRenderer->MeshSource == MetaCore::MetaCoreMeshSourceKind::Asset, "renderable node should use asset mesh source");
|
||||||
|
MetaCoreExpect(instantiatedRenderable->MeshRenderer->MeshAssetGuid.IsValid(), "renderable node should bind mesh asset guid");
|
||||||
|
MetaCoreExpect(!instantiatedRenderable->MeshRenderer->MaterialAssetGuids.empty(), "renderable node should bind material assets");
|
||||||
MetaCoreExpect(
|
MetaCoreExpect(
|
||||||
instantiatedRoot->MeshRenderer->SourceModelPath == (std::filesystem::path("Assets") / "Pump.gltf").generic_string(),
|
instantiatedRenderable->MeshRenderer->SourceModelPath == (std::filesystem::path("Assets") / "Pump.gltf").generic_string(),
|
||||||
"导入模型实例应记录源模型路径"
|
"renderable node should record source model path"
|
||||||
);
|
);
|
||||||
MetaCoreExpect(
|
MetaCoreExpect(
|
||||||
instantiatedRoot->MeshRenderer->BaseColorTexturePath == (std::filesystem::path("Textures") / "PumpBaseColor.png").generic_string(),
|
instantiatedRenderable->MeshRenderer->BaseColorTexturePath == (std::filesystem::path("Textures") / "PumpBaseColor.png").generic_string(),
|
||||||
"导入模型实例应带入基础颜色贴图路径"
|
"renderable node should record base color texture path"
|
||||||
);
|
);
|
||||||
MetaCoreExpect(instantiatedRoot->MeshRenderer->BaseColor.x == 1.0F, "导入模型实例应带入默认材质基础颜色");
|
MetaCoreExpect(instantiatedRenderable->MeshRenderer->BaseColor.x == 1.0F, "renderable node should carry base color");
|
||||||
MetaCoreExpect(editorContext.GetActiveObjectId() == *instantiatedRootId, "实例化后应选中新对象");
|
MetaCoreExpect(editorContext.GetActiveObjectId() == *instantiatedRootId, "实例化后应选中新对象");
|
||||||
|
|
||||||
coreServicesModule->Shutdown(moduleRegistry);
|
coreServicesModule->Shutdown(moduleRegistry);
|
||||||
@ -981,8 +1048,9 @@ void MetaCoreTestInstantiateMultiNodeModelAssetIntoScene() {
|
|||||||
|
|
||||||
MetaCore::MetaCoreImportedGltfMeshDocument meshDocument;
|
MetaCore::MetaCoreImportedGltfMeshDocument meshDocument;
|
||||||
meshDocument.Name = "ValveMesh";
|
meshDocument.Name = "ValveMesh";
|
||||||
meshDocument.PrimitiveCount = 1;
|
meshDocument.PrimitiveCount = 2;
|
||||||
meshDocument.MaterialSlots.push_back(0);
|
meshDocument.MaterialSlots.push_back(0);
|
||||||
|
meshDocument.MaterialSlots.push_back(1);
|
||||||
document.Meshes.push_back(meshDocument);
|
document.Meshes.push_back(meshDocument);
|
||||||
|
|
||||||
MetaCore::MetaCoreMaterialAssetDocument materialAsset;
|
MetaCore::MetaCoreMaterialAssetDocument materialAsset;
|
||||||
@ -990,9 +1058,26 @@ void MetaCoreTestInstantiateMultiNodeModelAssetIntoScene() {
|
|||||||
materialAsset.Name = "ValveMaterial";
|
materialAsset.Name = "ValveMaterial";
|
||||||
document.GeneratedMaterialAssets.push_back(materialAsset);
|
document.GeneratedMaterialAssets.push_back(materialAsset);
|
||||||
|
|
||||||
|
MetaCore::MetaCoreMaterialAssetDocument secondaryMaterialAsset;
|
||||||
|
secondaryMaterialAsset.AssetGuid = MetaCore::MetaCoreAssetGuid::Generate();
|
||||||
|
secondaryMaterialAsset.Name = "ValveSecondaryMaterial";
|
||||||
|
document.GeneratedMaterialAssets.push_back(secondaryMaterialAsset);
|
||||||
|
|
||||||
MetaCore::MetaCoreMeshAssetDocument meshAsset;
|
MetaCore::MetaCoreMeshAssetDocument meshAsset;
|
||||||
meshAsset.AssetGuid = MetaCore::MetaCoreAssetGuid::Generate();
|
meshAsset.AssetGuid = MetaCore::MetaCoreAssetGuid::Generate();
|
||||||
meshAsset.Name = "ValveMesh";
|
meshAsset.Name = "ValveMesh";
|
||||||
|
MetaCore::MetaCoreMeshSubMeshDocument firstSubMesh;
|
||||||
|
firstSubMesh.Name = "Primitive_0";
|
||||||
|
firstSubMesh.MaterialSlotIndex = 0;
|
||||||
|
firstSubMesh.FirstIndex = 0;
|
||||||
|
firstSubMesh.IndexCount = 3;
|
||||||
|
meshAsset.SubMeshes.push_back(firstSubMesh);
|
||||||
|
MetaCore::MetaCoreMeshSubMeshDocument secondSubMesh;
|
||||||
|
secondSubMesh.Name = "Primitive_1";
|
||||||
|
secondSubMesh.MaterialSlotIndex = 1;
|
||||||
|
secondSubMesh.FirstIndex = 3;
|
||||||
|
secondSubMesh.IndexCount = 3;
|
||||||
|
meshAsset.SubMeshes.push_back(secondSubMesh);
|
||||||
document.GeneratedMeshAssets.push_back(meshAsset);
|
document.GeneratedMeshAssets.push_back(meshAsset);
|
||||||
|
|
||||||
const auto payload = MetaCore::MetaCoreSerializeToBytes(document, reflectionRegistry->GetTypeRegistry());
|
const auto payload = MetaCore::MetaCoreSerializeToBytes(document, reflectionRegistry->GetTypeRegistry());
|
||||||
@ -1021,20 +1106,27 @@ void MetaCoreTestInstantiateMultiNodeModelAssetIntoScene() {
|
|||||||
|
|
||||||
const MetaCore::MetaCoreGameObject* instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
const MetaCore::MetaCoreGameObject* instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
||||||
MetaCoreExpect(instantiatedRoot != nullptr, "多节点实例化后应能找到根对象");
|
MetaCoreExpect(instantiatedRoot != nullptr, "多节点实例化后应能找到根对象");
|
||||||
MetaCoreExpect(instantiatedRoot->Name == "AssemblyRoot", "多节点实例化根对象应保留节点名称");
|
MetaCoreExpect(instantiatedRoot->Name == "Assembly.gltf", "multi-node model root should use source file name");
|
||||||
MetaCoreExpect(!instantiatedRoot->MeshRenderer.has_value(), "无 mesh 的根节点不应强制带 MeshRenderer");
|
MetaCoreExpect(!instantiatedRoot->MeshRenderer.has_value(), "asset root should not force MeshRenderer");
|
||||||
|
|
||||||
|
const auto importedRootIterator = std::find_if(scene.GetGameObjects().begin(), scene.GetGameObjects().end(), [&](const MetaCore::MetaCoreGameObject& object) {
|
||||||
|
return object.Name == "AssemblyRoot";
|
||||||
|
});
|
||||||
|
MetaCoreExpect(importedRootIterator != scene.GetGameObjects().end(), "multi-node instantiation should create imported root node");
|
||||||
|
MetaCoreExpect(importedRootIterator->ParentId == instantiatedRoot->Id, "imported root node should be parented under asset root");
|
||||||
|
MetaCoreExpect(!importedRootIterator->MeshRenderer.has_value(), "imported empty root should not force MeshRenderer");
|
||||||
|
|
||||||
const auto childIterator = std::find_if(scene.GetGameObjects().begin(), scene.GetGameObjects().end(), [&](const MetaCore::MetaCoreGameObject& object) {
|
const auto childIterator = std::find_if(scene.GetGameObjects().begin(), scene.GetGameObjects().end(), [&](const MetaCore::MetaCoreGameObject& object) {
|
||||||
return object.Name == "Valve_A";
|
return object.Name == "Valve_A";
|
||||||
});
|
});
|
||||||
MetaCoreExpect(childIterator != scene.GetGameObjects().end(), "多节点实例化应创建子节点对象");
|
MetaCoreExpect(childIterator != scene.GetGameObjects().end(), "multi-node instantiation should create child node object");
|
||||||
MetaCoreExpect(childIterator->ParentId == instantiatedRoot->Id, "子节点应挂在根节点下");
|
MetaCoreExpect(childIterator->ParentId == importedRootIterator->Id, "child node should be parented under imported root node");
|
||||||
MetaCoreExpect(childIterator->MeshRenderer.has_value(), "带 mesh 的子节点应带 MeshRenderer");
|
MetaCoreExpect(childIterator->MeshRenderer.has_value(), "mesh child should have MeshRenderer");
|
||||||
MetaCoreExpect(childIterator->MeshRenderer->MeshAssetGuid == meshAsset.AssetGuid, "子节点应绑定生成 mesh 资源");
|
MetaCoreExpect(childIterator->MeshRenderer->MeshAssetGuid == meshAsset.AssetGuid, "child node should bind generated mesh asset");
|
||||||
MetaCoreExpect(childIterator->MeshRenderer->MaterialAssetGuids.size() == 1, "子节点应绑定材质槽位");
|
MetaCoreExpect(childIterator->MeshRenderer->MaterialAssetGuids.size() == 2, "child node should bind all material slots");
|
||||||
MetaCoreExpect(childIterator->MeshRenderer->MaterialAssetGuids.front() == materialAsset.AssetGuid, "子节点应绑定生成材质资源");
|
MetaCoreExpect(childIterator->MeshRenderer->MaterialAssetGuids.front() == materialAsset.AssetGuid, "child node should bind generated material asset");
|
||||||
MetaCoreExpect(editorContext.GetActiveObjectId() == instantiatedRoot->Id, "多节点实例化后应选中根对象");
|
MetaCoreExpect(childIterator->MeshRenderer->MaterialAssetGuids[1] == secondaryMaterialAsset.AssetGuid, "child node should bind secondary material asset");
|
||||||
|
MetaCoreExpect(editorContext.GetActiveObjectId() == instantiatedRoot->Id, "multi-node instantiation should select asset root");
|
||||||
coreServicesModule->Shutdown(moduleRegistry);
|
coreServicesModule->Shutdown(moduleRegistry);
|
||||||
moduleRegistry.ShutdownServices();
|
moduleRegistry.ShutdownServices();
|
||||||
_putenv_s("METACORE_PROJECT_PATH", "");
|
_putenv_s("METACORE_PROJECT_PATH", "");
|
||||||
@ -1105,11 +1197,14 @@ void MetaCoreTestModelReimportKeepsGeneratedAssetReferencesStable() {
|
|||||||
MetaCoreExpect(instantiatedRootId.has_value(), "应能实例化模型资源");
|
MetaCoreExpect(instantiatedRootId.has_value(), "应能实例化模型资源");
|
||||||
|
|
||||||
const MetaCore::MetaCoreGameObject* instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
const MetaCore::MetaCoreGameObject* instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
||||||
MetaCoreExpect(instantiatedRoot != nullptr && instantiatedRoot->MeshRenderer.has_value(), "应能找到实例化后的模型对象");
|
MetaCoreExpect(instantiatedRoot != nullptr, "instantiated model root should exist");
|
||||||
|
const std::vector<MetaCore::MetaCoreId> instantiatedChildren = scene.GetChildrenOf(*instantiatedRootId);
|
||||||
const MetaCore::MetaCoreAssetGuid originalMeshGuid = instantiatedRoot->MeshRenderer->MeshAssetGuid;
|
MetaCoreExpect(instantiatedChildren.size() == 1, "instantiated model root should contain renderable child");
|
||||||
const MetaCore::MetaCoreAssetGuid originalMaterialGuid = instantiatedRoot->MeshRenderer->MaterialAssetGuids.front();
|
const MetaCore::MetaCoreGameObject* instantiatedRenderable = scene.FindGameObject(instantiatedChildren.front());
|
||||||
|
MetaCoreExpect(instantiatedRenderable != nullptr && instantiatedRenderable->MeshRenderer.has_value(), "instantiated renderable model object should exist");
|
||||||
|
|
||||||
|
const MetaCore::MetaCoreAssetGuid originalMeshGuid = instantiatedRenderable->MeshRenderer->MeshAssetGuid;
|
||||||
|
const MetaCore::MetaCoreAssetGuid originalMaterialGuid = instantiatedRenderable->MeshRenderer->MaterialAssetGuids.front();
|
||||||
{
|
{
|
||||||
std::ofstream gltfFile(modelPath, std::ios::trunc);
|
std::ofstream gltfFile(modelPath, std::ios::trunc);
|
||||||
gltfFile
|
gltfFile
|
||||||
@ -1145,11 +1240,12 @@ void MetaCoreTestModelReimportKeepsGeneratedAssetReferencesStable() {
|
|||||||
MetaCoreExpect(refreshedDocument.GeneratedMaterialAssets.front().AssetGuid == originalMaterialGuid, "重导入后材质子资源 GUID 应保持稳定");
|
MetaCoreExpect(refreshedDocument.GeneratedMaterialAssets.front().AssetGuid == originalMaterialGuid, "重导入后材质子资源 GUID 应保持稳定");
|
||||||
|
|
||||||
instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
instantiatedRoot = scene.FindGameObject(*instantiatedRootId);
|
||||||
MetaCoreExpect(instantiatedRoot != nullptr && instantiatedRoot->MeshRenderer.has_value(), "重导入后场景实例仍应存在");
|
MetaCoreExpect(instantiatedRoot != nullptr, "reimport should keep model root alive");
|
||||||
MetaCoreExpect(instantiatedRoot->MeshRenderer->MeshAssetGuid == originalMeshGuid, "重导入后场景实例的 mesh 引用应保持");
|
instantiatedRenderable = scene.FindGameObject(instantiatedChildren.front());
|
||||||
MetaCoreExpect(!instantiatedRoot->MeshRenderer->MaterialAssetGuids.empty(), "重导入后场景实例应保留材质引用");
|
MetaCoreExpect(instantiatedRenderable != nullptr && instantiatedRenderable->MeshRenderer.has_value(), "reimport should keep renderable instance alive");
|
||||||
MetaCoreExpect(instantiatedRoot->MeshRenderer->MaterialAssetGuids.front() == originalMaterialGuid, "重导入后场景实例的材质引用应保持");
|
MetaCoreExpect(instantiatedRenderable->MeshRenderer->MeshAssetGuid == originalMeshGuid, "reimport should keep mesh reference stable");
|
||||||
|
MetaCoreExpect(!instantiatedRenderable->MeshRenderer->MaterialAssetGuids.empty(), "reimport should keep material references");
|
||||||
|
MetaCoreExpect(instantiatedRenderable->MeshRenderer->MaterialAssetGuids.front() == originalMaterialGuid, "reimport should keep material reference stable");
|
||||||
coreServicesModule->Shutdown(moduleRegistry);
|
coreServicesModule->Shutdown(moduleRegistry);
|
||||||
moduleRegistry.ShutdownServices();
|
moduleRegistry.ShutdownServices();
|
||||||
_putenv_s("METACORE_PROJECT_PATH", "");
|
_putenv_s("METACORE_PROJECT_PATH", "");
|
||||||
|
|||||||
89894
third_party/entt/entt.hpp
vendored
Normal file
89894
third_party/entt/entt.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ namespace {
|
|||||||
MetaCore::MetaCoreSceneDocument document;
|
MetaCore::MetaCoreSceneDocument document;
|
||||||
document.Name = "Main";
|
document.Name = "Main";
|
||||||
const MetaCore::MetaCoreScene scene = MetaCore::MetaCoreCreateDefaultScene();
|
const MetaCore::MetaCoreScene scene = MetaCore::MetaCoreCreateDefaultScene();
|
||||||
document.GameObjects = scene.GetGameObjects();
|
document.GameObjects = scene.CaptureSnapshot().GameObjects;
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
"version-string": "1.0.0",
|
"version-string": "1.0.0",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"glm",
|
"glm",
|
||||||
|
"entt",
|
||||||
{
|
{
|
||||||
"name": "imgui",
|
"name": "imgui",
|
||||||
"default-features": false,
|
"default-features": false,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user