#pragma once #include "IViewportHostService.h" #include "ViewportHostRenderTargets.h" #include #include #include #include #include namespace XCEngine { namespace Editor { struct ViewportRenderFallbackPolicy { const char* statusText = nullptr; Math::Color clearColor = Math::Color::Black(); bool shouldClear = false; bool setStatusIfEmpty = false; bool invalidateObjectIdFrame = true; }; enum class SceneViewportRenderFailure { MissingSceneViewCamera, NoActiveScene, SceneRendererFailed }; enum class GameViewportRenderFailure { NoActiveScene, NoCameraInScene, SceneRendererFailed }; inline void SetViewportStatusIfEmpty(std::string& statusText, const char* message) { if (statusText.empty()) { statusText = message; } } inline void ApplyViewportFailureStatus( std::string& statusText, const ViewportRenderFallbackPolicy& policy) { if (policy.statusText == nullptr) { return; } if (policy.setStatusIfEmpty) { SetViewportStatusIfEmpty(statusText, policy.statusText); return; } statusText = policy.statusText; } inline void InvalidateViewportObjectIdFrame(ViewportRenderTargets& targets) { targets.hasValidObjectIdFrame = false; } inline ViewportRenderFallbackPolicy BuildViewportRenderTargetUnavailablePolicy() { ViewportRenderFallbackPolicy policy = {}; policy.statusText = "Viewport render target is unavailable"; return policy; } inline ViewportRenderFallbackPolicy BuildSceneViewportRenderFailurePolicy( SceneViewportRenderFailure failure) { ViewportRenderFallbackPolicy policy = {}; policy.shouldClear = true; switch (failure) { case SceneViewportRenderFailure::MissingSceneViewCamera: policy.statusText = "Scene view camera is unavailable"; policy.clearColor = Math::Color(0.18f, 0.07f, 0.07f, 1.0f); break; case SceneViewportRenderFailure::NoActiveScene: policy.statusText = "No active scene"; policy.clearColor = Math::Color(0.07f, 0.08f, 0.10f, 1.0f); break; case SceneViewportRenderFailure::SceneRendererFailed: policy.statusText = "Scene renderer failed"; policy.clearColor = Math::Color(0.18f, 0.07f, 0.07f, 1.0f); policy.setStatusIfEmpty = true; break; default: break; } return policy; } inline ViewportRenderFallbackPolicy BuildGameViewportRenderFailurePolicy( GameViewportRenderFailure failure) { ViewportRenderFallbackPolicy policy = {}; policy.shouldClear = true; switch (failure) { case GameViewportRenderFailure::NoActiveScene: policy.statusText = "No active scene"; policy.clearColor = Math::Color(0.07f, 0.08f, 0.10f, 1.0f); break; case GameViewportRenderFailure::NoCameraInScene: policy.statusText = "No camera in scene"; policy.clearColor = Math::Color(0.10f, 0.09f, 0.08f, 1.0f); break; case GameViewportRenderFailure::SceneRendererFailed: policy.statusText = "Scene renderer failed"; policy.clearColor = Math::Color(0.18f, 0.07f, 0.07f, 1.0f); break; default: break; } return policy; } struct SceneViewportBuiltinPostProcessBuildResult { Rendering::BuiltinPostProcessRequest request = {}; const char* warningStatusText = nullptr; }; inline Rendering::Passes::InfiniteGridPassData BuildSceneViewportGridPassData( const SceneViewportOverlayData& overlay) { Rendering::Passes::InfiniteGridPassData data = {}; data.valid = overlay.valid; data.cameraPosition = overlay.cameraPosition; data.cameraForward = overlay.cameraForward; data.cameraRight = overlay.cameraRight; data.cameraUp = overlay.cameraUp; data.verticalFovDegrees = overlay.verticalFovDegrees; data.nearClipPlane = overlay.nearClipPlane; data.farClipPlane = overlay.farClipPlane; data.orbitDistance = overlay.orbitDistance; return data; } inline SceneViewportBuiltinPostProcessBuildResult BuildSceneViewportBuiltinPostProcess( const SceneViewportOverlayData& overlay, const std::vector& selectedObjectIds, bool hasObjectIdShaderView, bool debugSelectionMask = false) { SceneViewportBuiltinPostProcessBuildResult result = {}; if (!overlay.valid) { return result; } result.request.gridPassData = BuildSceneViewportGridPassData(overlay); result.request.selectedObjectIds = selectedObjectIds; result.request.outlineStyle = {}; result.request.outlineStyle.outlineColor = Math::Color(1.0f, 0.4f, 0.0f, 1.0f); result.request.outlineStyle.outlineWidthPixels = 2.0f; result.request.outlineStyle.debugSelectionMask = debugSelectionMask; if (!selectedObjectIds.empty() && !debugSelectionMask && !hasObjectIdShaderView) { result.warningStatusText = "Scene object id shader view is unavailable"; } return result; } inline void ApplySceneViewportRenderRequestSetup( const ViewportRenderTargets& targets, const Rendering::BuiltinPostProcessRequest* builtinPostProcess, Rendering::RenderPassSequence* postPasses, Rendering::CameraRenderRequest& request) { request.preScenePasses = nullptr; request.postScenePasses = nullptr; request.overlayPasses = nullptr; request.objectId = {}; request.builtinPostProcess = {}; if (postPasses != nullptr && postPasses->GetPassCount() > 0) { request.postScenePasses = postPasses; } if (builtinPostProcess != nullptr && builtinPostProcess->IsRequested()) { request.builtinPostProcess = *builtinPostProcess; request.builtinPostProcess.objectIdTextureView = targets.objectIdShaderView; } if (targets.objectIdView == nullptr) { return; } request.objectId.surface = BuildViewportObjectIdSurface(targets); request.objectId.surface.SetRenderArea(request.surface.GetRenderArea()); } inline void MarkSceneViewportRenderSuccess( ViewportRenderTargets& targets, const Rendering::CameraRenderRequest& request) { targets.colorState = RHI::ResourceStates::PixelShaderResource; targets.objectIdState = RHI::ResourceStates::PixelShaderResource; targets.hasValidObjectIdFrame = request.objectId.IsRequested(); } inline void MarkGameViewportRenderSuccess(ViewportRenderTargets& targets) { targets.colorState = RHI::ResourceStates::PixelShaderResource; targets.hasValidObjectIdFrame = false; } } // namespace Editor } // namespace XCEngine