#include "MetaCoreRender/MetaCorePandaSceneBridge.h" #include "MetaCoreRender/MetaCoreRenderDevice.h" #include "MetaCoreRender/MetaCoreRenderTypes.h" #include "MetaCoreScene/MetaCoreComponents.h" #include "MetaCoreScene/MetaCoreScene.h" #include "ambientLight.h" #include "camera.h" #include "directionalLight.h" #include "lineSegs.h" #include "loader.h" #include "nodePath.h" #include "perspectiveLens.h" #include "pandaNode.h" #include "windowFramework.h" #define GLM_ENABLE_EXPERIMENTAL #include #include #include #include #include namespace MetaCore { namespace { glm::mat4 MetaCoreBuildBasisSwapMatrix() { glm::mat4 basis(1.0F); basis[0] = glm::vec4(1.0F, 0.0F, 0.0F, 0.0F); basis[1] = glm::vec4(0.0F, 0.0F, 1.0F, 0.0F); basis[2] = glm::vec4(0.0F, 1.0F, 0.0F, 0.0F); basis[3] = glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); return basis; } LMatrix4f MetaCoreConvertTransformToPanda(const MetaCoreTransformComponent& transform) { const glm::mat4 translation = glm::translate(glm::mat4(1.0F), transform.Position); const glm::mat4 rotation = glm::yawPitchRoll( glm::radians(transform.RotationEulerDegrees.y), glm::radians(transform.RotationEulerDegrees.x), glm::radians(transform.RotationEulerDegrees.z) ); const glm::mat4 scale = glm::scale(glm::mat4(1.0F), transform.Scale); const glm::mat4 metaCoreMatrix = translation * rotation * scale; const glm::mat4 basis = MetaCoreBuildBasisSwapMatrix(); const glm::mat4 pandaMatrix = basis * metaCoreMatrix * basis; LMatrix4f result; for (int row = 0; row < 4; ++row) { for (int column = 0; column < 4; ++column) { result.set_cell(row, column, pandaMatrix[column][row]); } } return result; } LPoint3f MetaCoreToPandaPoint(const glm::vec3& value) { return LPoint3f(value.x, value.z, value.y); } LVector3f MetaCoreToPandaVector(const glm::vec3& value) { return LVector3f(value.x, value.z, value.y); } NodePath MetaCoreCreateGridNode(const NodePath& parentNode) { LineSegs gridBuilder("MetaCoreGrid"); gridBuilder.set_thickness(1.0F); constexpr int gridHalfExtent = 10; for (int lineIndex = -gridHalfExtent; lineIndex <= gridHalfExtent; ++lineIndex) { const bool isAxisLine = (lineIndex == 0); gridBuilder.set_color(isAxisLine ? 0.42F : 0.30F, isAxisLine ? 0.45F : 0.33F, isAxisLine ? 0.50F : 0.36F, 1.0F); gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast(lineIndex), 0.0F, static_cast(-gridHalfExtent)))); gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast(lineIndex), 0.0F, static_cast(gridHalfExtent)))); gridBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(static_cast(-gridHalfExtent), 0.0F, static_cast(lineIndex)))); gridBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(static_cast(gridHalfExtent), 0.0F, static_cast(lineIndex)))); } return parentNode.attach_new_node(gridBuilder.create()); } NodePath MetaCoreCreateAxisNode(const NodePath& parentNode) { LineSegs axisBuilder("MetaCoreAxis"); axisBuilder.set_thickness(3.0F); axisBuilder.set_color(0.92F, 0.26F, 0.26F, 1.0F); axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(2.0F, 0.0F, 0.0F))); axisBuilder.set_color(0.28F, 0.86F, 0.36F, 1.0F); axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 2.0F, 0.0F))); axisBuilder.set_color(0.32F, 0.56F, 0.96F, 1.0F); axisBuilder.move_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 0.0F))); axisBuilder.draw_to(MetaCoreToPandaPoint(glm::vec3(0.0F, 0.0F, 2.0F))); return parentNode.attach_new_node(axisBuilder.create()); } } // namespace class MetaCorePandaSceneBridge::MetaCorePandaSceneBridgeImpl { public: struct MetaCorePandaObjectState { NodePath RootNode{}; NodePath MeshNode{}; NodePath LightNode{}; }; MetaCoreRenderDevice* RenderDevice = nullptr; NodePath GridNode{}; NodePath AxisNode{}; NodePath AmbientLightNode{}; MetaCoreId SelectedObjectId = 0; std::unordered_map ObjectStates{}; }; MetaCorePandaSceneBridge::MetaCorePandaSceneBridge() : Impl_(std::make_unique()) { } MetaCorePandaSceneBridge::~MetaCorePandaSceneBridge() { Shutdown(); } bool MetaCorePandaSceneBridge::Initialize(MetaCoreRenderDevice& renderDevice) { Shutdown(); auto* windowFrameworkHandle = static_cast(renderDevice.GetNativeWindowFrameworkHandle()); auto* sceneRootHandle = static_cast(renderDevice.GetNativeSceneRootHandle()); if (windowFrameworkHandle == nullptr || sceneRootHandle == nullptr || sceneRootHandle->is_empty()) { return false; } Impl_->RenderDevice = &renderDevice; Impl_->GridNode = MetaCoreCreateGridNode(*sceneRootHandle); Impl_->AxisNode = MetaCoreCreateAxisNode(*sceneRootHandle); Impl_->GridNode.set_light_off(1); Impl_->AxisNode.set_light_off(1); PT(AmbientLight) ambientLight = new AmbientLight("MetaCoreAmbientLight"); ambientLight->set_color(LColor(0.85F, 0.85F, 0.85F, 1.0F)); Impl_->AmbientLightNode = sceneRootHandle->attach_new_node(ambientLight); sceneRootHandle->set_light(Impl_->AmbientLightNode); return true; } void MetaCorePandaSceneBridge::Shutdown() { if (Impl_ == nullptr) { return; } for (auto& [objectId, objectState] : Impl_->ObjectStates) { (void)objectId; if (!objectState.RootNode.is_empty()) { objectState.RootNode.remove_node(); } } Impl_->ObjectStates.clear(); if (!Impl_->AmbientLightNode.is_empty()) { Impl_->AmbientLightNode.remove_node(); Impl_->AmbientLightNode = NodePath(); } if (!Impl_->AxisNode.is_empty()) { Impl_->AxisNode.remove_node(); Impl_->AxisNode = NodePath(); } if (!Impl_->GridNode.is_empty()) { Impl_->GridNode.remove_node(); Impl_->GridNode = NodePath(); } Impl_->RenderDevice = nullptr; Impl_->SelectedObjectId = 0; } void MetaCorePandaSceneBridge::SyncScene(const MetaCoreScene& scene) { if (Impl_->RenderDevice == nullptr) { return; } auto* windowFrameworkHandle = static_cast(Impl_->RenderDevice->GetNativeWindowFrameworkHandle()); auto* sceneRootHandle = static_cast(Impl_->RenderDevice->GetNativeSceneRootHandle()); if (windowFrameworkHandle == nullptr || sceneRootHandle == nullptr || sceneRootHandle->is_empty()) { return; } std::unordered_set aliveObjectIds; for (const MetaCoreGameObject& gameObject : scene.GetGameObjects()) { aliveObjectIds.insert(gameObject.Id); auto [iterator, inserted] = Impl_->ObjectStates.try_emplace(gameObject.Id); MetaCorePandaSceneBridgeImpl::MetaCorePandaObjectState& objectState = iterator->second; if (inserted || objectState.RootNode.is_empty()) { PT(PandaNode) rootNode = new PandaNode(gameObject.Name); objectState.RootNode = sceneRootHandle->attach_new_node(rootNode); } objectState.RootNode.set_name(gameObject.Name); objectState.RootNode.set_mat(MetaCoreConvertTransformToPanda(gameObject.Transform)); if (gameObject.ParentId != 0) { const auto parentIterator = Impl_->ObjectStates.find(gameObject.ParentId); if (parentIterator != Impl_->ObjectStates.end() && !parentIterator->second.RootNode.is_empty()) { objectState.RootNode.reparent_to(parentIterator->second.RootNode); } else { objectState.RootNode.reparent_to(*sceneRootHandle); } } else { objectState.RootNode.reparent_to(*sceneRootHandle); } if (gameObject.MeshRenderer.has_value()) { if (objectState.MeshNode.is_empty()) { objectState.MeshNode = windowFrameworkHandle->load_model(objectState.RootNode, Filename("models/box")); } if (!objectState.MeshNode.is_empty()) { objectState.MeshNode.set_texture_off(1); objectState.MeshNode.set_material_off(1); objectState.MeshNode.set_shader_off(1); objectState.MeshNode.set_light_off(1); objectState.MeshNode.set_two_sided(true); objectState.MeshNode.set_color( gameObject.MeshRenderer->BaseColor.r, gameObject.MeshRenderer->BaseColor.g, gameObject.MeshRenderer->BaseColor.b, 1.0F ); if (gameObject.MeshRenderer->Visible) { objectState.MeshNode.show(); } else { objectState.MeshNode.hide(); } if (gameObject.Id == Impl_->SelectedObjectId) { objectState.MeshNode.set_color_scale(1.18F, 1.02F, 0.72F, 1.0F); } else { objectState.MeshNode.clear_color_scale(); } } } else if (!objectState.MeshNode.is_empty()) { objectState.MeshNode.remove_node(); objectState.MeshNode = NodePath(); } if (gameObject.Light.has_value()) { if (objectState.LightNode.is_empty()) { PT(DirectionalLight) directionalLight = new DirectionalLight(gameObject.Name); objectState.LightNode = objectState.RootNode.attach_new_node(directionalLight); sceneRootHandle->set_light(objectState.LightNode); } auto* directionalLight = DCAST(DirectionalLight, objectState.LightNode.node()); if (directionalLight != nullptr) { directionalLight->set_color(LColor( gameObject.Light->Color.r * gameObject.Light->Intensity, gameObject.Light->Color.g * gameObject.Light->Intensity, gameObject.Light->Color.b * gameObject.Light->Intensity, 1.0F )); } } else if (!objectState.LightNode.is_empty()) { sceneRootHandle->clear_light(objectState.LightNode); objectState.LightNode.remove_node(); objectState.LightNode = NodePath(); } } for (auto iterator = Impl_->ObjectStates.begin(); iterator != Impl_->ObjectStates.end();) { if (!aliveObjectIds.contains(iterator->first)) { if (!iterator->second.RootNode.is_empty()) { iterator->second.RootNode.remove_node(); } iterator = Impl_->ObjectStates.erase(iterator); } else { ++iterator; } } } void MetaCorePandaSceneBridge::ApplySceneView(const MetaCoreSceneView& sceneView) { if (Impl_->RenderDevice == nullptr) { return; } auto* editorCameraHandle = static_cast(Impl_->RenderDevice->GetNativeEditorCameraHandle()); if (editorCameraHandle == nullptr || editorCameraHandle->is_empty()) { return; } Impl_->SelectedObjectId = sceneView.SelectedObjectId; editorCameraHandle->set_pos(MetaCoreToPandaPoint(sceneView.CameraPosition)); editorCameraHandle->look_at(MetaCoreToPandaPoint(sceneView.CameraTarget), MetaCoreToPandaVector(sceneView.CameraUp)); auto* cameraNode = DCAST(Camera, editorCameraHandle->node()); if (cameraNode != nullptr) { auto* perspectiveLens = DCAST(PerspectiveLens, cameraNode->get_lens()); if (perspectiveLens != nullptr) { perspectiveLens->set_fov(sceneView.VerticalFieldOfViewDegrees); } } } } // namespace MetaCore