#pragma once #include "Rendering/Viewport/SceneViewportRenderRequest.h" #include "Rendering/Viewport/SceneViewportPassSpecs.h" #include "Rendering/Viewport/ViewportRenderTargets.h" #include #include #include #include #include #include #include #include namespace XCEngine::UI::Editor::App { struct SceneViewportRenderPlan { ::XCEngine::Rendering::RenderPassSequence postScenePasses = {}; bool usesGridPass = false; bool usesSelectionOutline = false; bool hasClearColorOverride = true; ::XCEngine::Math::Color clearColorOverride = ::XCEngine::Math::Color(0.27f, 0.27f, 0.27f, 1.0f); bool HasPostScenePasses() const { return postScenePasses.GetPassCount() > 0u; } }; using SceneViewportGridPassFactory = std::function< std::unique_ptr<::XCEngine::Rendering::RenderPass>( const SceneViewportGridPassData&)>; using SceneViewportSelectionOutlinePassFactory = std::function< std::unique_ptr<::XCEngine::Rendering::RenderPass>( ViewportRenderTargets*, const std::vector&, const SceneViewportSelectionOutlineStyle&)>; using SceneViewportSelectedHelpersPassFactory = std::function< std::unique_ptr<::XCEngine::Rendering::RenderPass>( const SceneViewportRenderRequest&)>; struct SceneViewportRenderPlanBuildResult { SceneViewportRenderPlan plan = {}; const char* warningStatusText = nullptr; }; inline SceneViewportSelectionOutlineStyle BuildSceneViewportSelectionOutlineStyle( bool debugSelectionMask = false) { SceneViewportSelectionOutlineStyle style = {}; style.debugSelectionMask = debugSelectionMask; return style; } inline bool CanRenderSceneViewportSelectionOutline( const ViewportRenderTargets& targets) { return targets.selectionMaskView != nullptr && targets.selectionMaskShaderView != nullptr && targets.depthView != nullptr && targets.depthShaderView != nullptr; } inline SceneViewportGridPassData BuildSceneViewportGridPassData( const SceneViewportRenderRequest& request) { SceneViewportGridPassData data = {}; if (request.camera == nullptr || request.camera->GetGameObject() == nullptr || request.camera->GetGameObject()->GetTransform() == nullptr) { return data; } const auto* transform = request.camera->GetGameObject()->GetTransform(); data.valid = true; data.cameraPosition = transform->GetPosition(); data.cameraForward = transform->GetForward(); data.cameraRight = transform->GetRight(); data.cameraUp = transform->GetUp(); data.verticalFovDegrees = request.camera->GetFieldOfView(); data.nearClipPlane = request.camera->GetNearClipPlane(); data.farClipPlane = request.camera->GetFarClipPlane(); data.orbitDistance = request.orbitDistance; return data; } inline SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan( ViewportRenderTargets& targets, const SceneViewportRenderRequest& request, const SceneViewportGridPassFactory& gridPassFactory, const SceneViewportSelectionOutlinePassFactory& selectionOutlinePassFactory, const SceneViewportSelectedHelpersPassFactory& selectedHelpersPassFactory) { SceneViewportRenderPlanBuildResult result = {}; const SceneViewportGridPassData gridPassData = BuildSceneViewportGridPassData(request); if (gridPassData.valid && gridPassFactory != nullptr) { std::unique_ptr<::XCEngine::Rendering::RenderPass> gridPass = gridPassFactory(gridPassData); if (gridPass != nullptr) { result.plan.postScenePasses.AddPass(std::move(gridPass)); result.plan.usesGridPass = true; } } if (request.selectedObjectIds.empty()) { return result; } if (selectionOutlinePassFactory == nullptr) { if (selectedHelpersPassFactory == nullptr) { result.warningStatusText = "Scene selection helper passes are unavailable"; } } else if (!CanRenderSceneViewportSelectionOutline(targets)) { result.warningStatusText = "Scene selection outline resources are unavailable"; } else { std::unique_ptr<::XCEngine::Rendering::RenderPass> selectionOutlinePass = selectionOutlinePassFactory( &targets, request.selectedObjectIds, BuildSceneViewportSelectionOutlineStyle( request.debugSelectionMask)); if (selectionOutlinePass != nullptr) { result.plan.postScenePasses.AddPass(std::move(selectionOutlinePass)); result.plan.usesSelectionOutline = true; } else { result.warningStatusText = "Scene selection outline pass creation failed"; } } if (selectedHelpersPassFactory == nullptr) { return result; } std::unique_ptr<::XCEngine::Rendering::RenderPass> selectedHelpersPass = selectedHelpersPassFactory(request); if (selectedHelpersPass != nullptr) { result.plan.postScenePasses.AddPass(std::move(selectedHelpersPass)); return result; } if (result.warningStatusText == nullptr) { result.warningStatusText = "Scene selected helper pass creation failed"; } return result; } inline void ApplySceneViewportRenderPlan( const ViewportRenderTargets& targets, SceneViewportRenderPlan& plan, ::XCEngine::Rendering::CameraFramePlan& framePlan) { framePlan.preScenePasses = nullptr; framePlan.postScenePasses = nullptr; framePlan.overlayPasses = nullptr; framePlan.request.objectId = {}; if (plan.HasPostScenePasses()) { framePlan.postScenePasses = &plan.postScenePasses; } if (targets.objectIdView == nullptr || targets.objectIdDepthView == nullptr) { framePlan.request.hasClearColorOverride = plan.hasClearColorOverride; framePlan.request.clearColorOverride = plan.clearColorOverride; return; } framePlan.request.objectId.surface = BuildViewportObjectIdSurface(targets); framePlan.request.objectId.surface.SetRenderArea( framePlan.request.surface.GetRenderArea()); framePlan.request.hasClearColorOverride = plan.hasClearColorOverride; framePlan.request.clearColorOverride = plan.clearColorOverride; } inline void MarkSceneViewportRenderSuccess( ViewportRenderTargets& targets, const SceneViewportRenderPlan& plan, const ::XCEngine::Rendering::CameraFramePlan& framePlan) { targets.colorState = ::XCEngine::RHI::ResourceStates::PixelShaderResource; targets.objectIdState = framePlan.request.objectId.IsRequested() ? ::XCEngine::RHI::ResourceStates::PixelShaderResource : ::XCEngine::RHI::ResourceStates::Common; targets.selectionMaskState = plan.usesSelectionOutline ? ::XCEngine::RHI::ResourceStates::PixelShaderResource : ::XCEngine::RHI::ResourceStates::Common; targets.hasValidObjectIdFrame = framePlan.request.objectId.IsRequested(); if (!targets.hasValidObjectIdFrame) { targets.objectIdFrameSerial = 0u; } } } // namespace XCEngine::UI::Editor::App