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