#include "Rendering/CameraRenderer.h" #include "Rendering/Passes/BuiltinObjectIdPass.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/RenderPipelineAsset.h" #include "Rendering/RenderSurface.h" #include "Scene/Scene.h" namespace XCEngine { namespace Rendering { namespace { bool InitializePassSequence( RenderPassSequence* sequence, const RenderContext& context, bool& initialized) { if (sequence == nullptr) { initialized = false; return true; } initialized = sequence->Initialize(context); if (!initialized) { sequence->Shutdown(); } return initialized; } void ShutdownPassSequence(RenderPassSequence* sequence, bool initialized) { if (sequence != nullptr && initialized) { sequence->Shutdown(); } } std::shared_ptr CreateDefaultPipelineAsset() { static const std::shared_ptr s_defaultPipelineAsset = std::make_shared(); return s_defaultPipelineAsset; } std::unique_ptr CreatePipelineFromAsset( const std::shared_ptr& pipelineAsset) { if (pipelineAsset != nullptr) { std::unique_ptr pipeline = pipelineAsset->CreatePipeline(); if (pipeline != nullptr) { return pipeline; } } return std::make_unique(); } } // namespace CameraRenderer::CameraRenderer() : CameraRenderer(CreateDefaultPipelineAsset()) { } CameraRenderer::CameraRenderer(std::unique_ptr pipeline) : CameraRenderer(std::move(pipeline), std::make_unique()) { } CameraRenderer::CameraRenderer( std::unique_ptr pipeline, std::unique_ptr objectIdPass) : m_pipelineAsset(nullptr) , m_objectIdPass(std::move(objectIdPass)) { if (m_objectIdPass == nullptr) { m_objectIdPass = std::make_unique(); } ResetPipeline(std::move(pipeline)); } CameraRenderer::CameraRenderer(std::shared_ptr pipelineAsset) : m_pipelineAsset(std::move(pipelineAsset)) , m_objectIdPass(std::make_unique()) { SetPipelineAsset(m_pipelineAsset); } CameraRenderer::~CameraRenderer() { if (m_pipeline) { m_pipeline->Shutdown(); } if (m_objectIdPass != nullptr) { m_objectIdPass->Shutdown(); } m_builtinPostProcessBuilder.Shutdown(); } void CameraRenderer::SetPipeline(std::unique_ptr pipeline) { m_pipelineAsset.reset(); ResetPipeline(std::move(pipeline)); } void CameraRenderer::SetPipelineAsset(std::shared_ptr pipelineAsset) { m_pipelineAsset = pipelineAsset != nullptr ? std::move(pipelineAsset) : CreateDefaultPipelineAsset(); ResetPipeline(CreatePipelineFromAsset(m_pipelineAsset)); } void CameraRenderer::SetObjectIdPass(std::unique_ptr objectIdPass) { if (m_objectIdPass != nullptr) { m_objectIdPass->Shutdown(); } m_objectIdPass = std::move(objectIdPass); if (m_objectIdPass == nullptr) { m_objectIdPass = std::make_unique(); } } void CameraRenderer::ResetPipeline(std::unique_ptr pipeline) { if (m_pipeline != nullptr) { m_pipeline->Shutdown(); } m_pipeline = std::move(pipeline); if (m_pipeline == nullptr) { m_pipelineAsset = CreateDefaultPipelineAsset(); m_pipeline = CreatePipelineFromAsset(m_pipelineAsset); } } bool CameraRenderer::Render( const CameraRenderRequest& request) { if (!request.IsValid() || m_pipeline == nullptr) { return false; } if (request.surface.GetRenderAreaWidth() == 0 || request.surface.GetRenderAreaHeight() == 0) { return false; } if (request.objectId.IsRequested() && !request.objectId.IsValid()) { return false; } if (request.builtinPostProcess.IsRequested() && request.builtinPostProcess.objectIdTextureView != nullptr && !request.objectId.IsRequested()) { return false; } RenderSceneData sceneData = m_sceneExtractor.ExtractForCamera( *request.scene, *request.camera, request.surface.GetRenderAreaWidth(), request.surface.GetRenderAreaHeight()); if (!sceneData.HasCamera()) { return false; } sceneData.cameraData.clearFlags = request.clearFlags; if (request.hasClearColorOverride) { sceneData.cameraData.clearColor = request.clearColorOverride; } const RenderPassContext passContext = { request.context, request.surface, sceneData }; bool preScenePassesInitialized = false; if (!InitializePassSequence( request.preScenePasses, request.context, preScenePassesInitialized)) { return false; } if (request.preScenePasses != nullptr && !request.preScenePasses->Execute(passContext)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (!m_pipeline->Render(request.context, request.surface, sceneData)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (request.objectId.IsRequested() && (m_objectIdPass == nullptr || !m_objectIdPass->Render(request.context, request.objectId.surface, sceneData))) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } bool postScenePassesInitialized = false; if (!InitializePassSequence( request.postScenePasses, request.context, postScenePassesInitialized)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (request.postScenePasses != nullptr && !request.postScenePasses->Execute(passContext)) { ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } RenderPassSequence builtinPostProcessPasses = {}; bool builtinPostProcessPassesInitialized = false; if (request.builtinPostProcess.IsRequested()) { const Passes::BuiltinPostProcessPassSequenceBuildResult buildResult = m_builtinPostProcessBuilder.Build( { request.builtinPostProcess.gridPassData, request.builtinPostProcess.objectIdTextureView, request.builtinPostProcess.selectedObjectIds, request.builtinPostProcess.outlineStyle }, builtinPostProcessPasses); if (!buildResult.valid || !InitializePassSequence( &builtinPostProcessPasses, request.context, builtinPostProcessPassesInitialized)) { ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (!builtinPostProcessPasses.Execute(passContext)) { ShutdownPassSequence(&builtinPostProcessPasses, builtinPostProcessPassesInitialized); ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } } ShutdownPassSequence(&builtinPostProcessPasses, builtinPostProcessPassesInitialized); ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return true; } } // namespace Rendering } // namespace XCEngine