Files
XCEngine/editor/app/Services/Engine/EngineSceneViewportBridge.cpp

188 lines
6.1 KiB
C++

#include "Engine/EngineSceneViewportBridge.h"
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Components/TransformComponent.h>
#include <XCEngine/Rendering/Execution/SceneRenderer.h>
#include <XCEngine/Rendering/Picking/RenderObjectIdRegistry.h>
#include <XCEngine/Scene/Scene.h>
#include <XCEngine/Scene/SceneManager.h>
#include <algorithm>
#include <cmath>
#include <vector>
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<Scene*> 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<EditorSceneObjectId>(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<GameObject>("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