#include "Engine/EngineSceneViewportBridge.h" #include #include #include #include #include #include #include #include #include #include namespace XCEngine::UI::Editor::App { namespace { using ::XCEngine::Components::GameObject; using ::XCEngine::Components::Scene; using ::XCEngine::Components::SceneManager; using ::XCEngine::Components::TransformComponent; using ::XCEngine::Math::Quaternion; using ::XCEngine::Math::Vector3; using ::XCEngine::Rendering::RenderObjectId; using ::XCEngine::Rendering::RenderObjectIdRegistry; Scene* ResolvePrimaryScene(SceneManager& sceneManager) { if (Scene* activeScene = sceneManager.GetActiveScene(); activeScene != nullptr) { return activeScene; } const std::vector scenes = sceneManager.GetAllScenes(); if (!scenes.empty() && scenes.front() != nullptr) { sceneManager.SetActiveScene(scenes.front()); return scenes.front(); } return nullptr; } } // namespace EngineSceneViewportBridge::~EngineSceneViewportBridge() = default; void EngineSceneViewportBridge::Shutdown() { m_sceneViewportCamera = nullptr; m_sceneViewportCameraObject.reset(); } SceneViewportFramePlanBuildStatus EngineSceneViewportBridge::BuildFramePlan( const SceneViewportRenderRequest& request, const ::XCEngine::Rendering::RenderContext& renderContext, const ::XCEngine::Rendering::RenderSurface& surface, ::XCEngine::Rendering::CameraFramePlan& outFramePlan) { outFramePlan = {}; if (!request.IsValid()) { return SceneViewportFramePlanBuildStatus::InvalidRequest; } Scene* scene = ResolvePrimaryScene(SceneManager::Get()); if (scene == nullptr) { return SceneViewportFramePlanBuildStatus::NoActiveScene; } if (!EnsureSceneViewportCamera()) { return SceneViewportFramePlanBuildStatus::Failed; } ConfigureSceneViewportCamera(request.camera); const std::vector<::XCEngine::Rendering::CameraFramePlan> framePlans = m_sceneViewportRenderer.BuildFramePlans( *scene, m_sceneViewportCamera, renderContext, surface); if (framePlans.empty() || !framePlans.front().IsValid()) { return SceneViewportFramePlanBuildStatus::Failed; } outFramePlan = framePlans.front(); return SceneViewportFramePlanBuildStatus::Success; } bool EngineSceneViewportBridge::RenderFramePlan( const ::XCEngine::Rendering::CameraFramePlan& framePlan) { return framePlan.IsValid() && m_sceneViewportRenderer.Render(framePlan); } bool EngineSceneViewportBridge::TryResolveActiveSceneRenderObjectId( RenderObjectId renderObjectId, EditorSceneObjectId& outRuntimeObjectId) const { outRuntimeObjectId = kInvalidEditorSceneObjectId; std::uint64_t runtimeObjectId = kInvalidEditorSceneObjectId; if (!RenderObjectIdRegistry::Get().TryResolveRuntimeObjectId( renderObjectId, runtimeObjectId)) { return false; } Scene* scene = ResolvePrimaryScene(SceneManager::Get()); GameObject* gameObject = scene != nullptr ? scene->FindByID(static_cast(runtimeObjectId)) : nullptr; if (gameObject == nullptr) { return false; } outRuntimeObjectId = gameObject->GetID(); return true; } bool EngineSceneViewportBridge::EnsureSceneViewportCamera() { if (m_sceneViewportCameraObject != nullptr && m_sceneViewportCamera != nullptr) { return true; } m_sceneViewportCamera = nullptr; m_sceneViewportCameraObject = std::make_unique("EditorSceneViewportCamera"); m_sceneViewportCamera = m_sceneViewportCameraObject->AddComponent< ::XCEngine::Components::CameraComponent>(); if (m_sceneViewportCamera == nullptr) { m_sceneViewportCameraObject.reset(); return false; } m_sceneViewportCamera->SetPrimary(false); m_sceneViewportCamera->SetProjectionType( ::XCEngine::Components::CameraProjectionType::Perspective); m_sceneViewportCamera->SetFieldOfView(60.0f); m_sceneViewportCamera->SetNearClipPlane(0.03f); m_sceneViewportCamera->SetFarClipPlane(2000.0f); return true; } void EngineSceneViewportBridge::ConfigureSceneViewportCamera( const EditorSceneCameraSnapshot& snapshot) { if (!EnsureSceneViewportCamera() || m_sceneViewportCameraObject == nullptr || m_sceneViewportCamera == nullptr) { return; } TransformComponent* transform = m_sceneViewportCameraObject->GetTransform(); if (transform == nullptr) { return; } Vector3 forward = snapshot.forward.SqrMagnitude() > ::XCEngine::Math::EPSILON ? snapshot.forward.Normalized() : Vector3::Forward(); Vector3 up = snapshot.up.SqrMagnitude() > ::XCEngine::Math::EPSILON ? snapshot.up.Normalized() : Vector3::Up(); if (Vector3::Cross(forward, up).SqrMagnitude() <= ::XCEngine::Math::EPSILON) { up = std::abs(Vector3::Dot(forward, Vector3::Up())) < 0.999f ? Vector3::Up() : Vector3::Right(); } transform->SetPosition(snapshot.position); transform->SetRotation(Quaternion::LookRotation(forward, up)); const float nearClipPlane = (std::max)(snapshot.nearClipPlane, 0.001f); const float farClipPlane = (std::max)(snapshot.farClipPlane, nearClipPlane + 0.001f); m_sceneViewportCamera->SetPrimary(false); m_sceneViewportCamera->SetProjectionType( ::XCEngine::Components::CameraProjectionType::Perspective); m_sceneViewportCamera->SetFieldOfView( std::clamp(snapshot.verticalFovDegrees, 1.0f, 179.0f)); m_sceneViewportCamera->SetNearClipPlane(nearClipPlane); m_sceneViewportCamera->SetFarClipPlane(farClipPlane); } } // namespace XCEngine::UI::Editor::App