using System; using XCEngine; using XCEngine.Rendering; namespace XCEngine.Rendering.Universal { public abstract class ScriptableRenderPass { private enum RecordedScenePhase { Opaque = 0, Skybox = 1, Transparent = 3 } private enum RecordedSceneInjectionPoint { BeforeOpaque = 0, AfterOpaque = 1, BeforeSkybox = 2, AfterSkybox = 3, BeforeTransparent = 4, AfterTransparent = 5 } private enum RecordedFullscreenPassType { ColorScale = 0, ShaderVector = 1 } protected ScriptableRenderPass() { } public RenderPassEvent renderPassEvent { get; protected set; } = RenderPassEvent.BeforeRenderingOpaques; public virtual bool SupportsStage( CameraFrameStage stage) { CameraFrameStage resolvedStage; return TryResolveStage( renderPassEvent, out resolvedStage) && resolvedStage == stage; } internal bool Record( ScriptableRenderContext context, RenderingData renderingData) { return RecordRenderGraph( context, renderingData); } protected abstract bool RecordRenderGraph( ScriptableRenderContext context, RenderingData renderingData); protected bool RecordScene( ScriptableRenderContext context) { return context != null && InternalCalls .Rendering_ScriptableRenderContext_RecordScene( context.nativeHandle); } protected bool RecordOpaqueScenePhase( ScriptableRenderContext context) { return RecordScenePhaseInternal( context, RecordedScenePhase.Opaque); } protected bool RecordSkyboxScenePhase( ScriptableRenderContext context) { return RecordScenePhaseInternal( context, RecordedScenePhase.Skybox); } protected bool RecordTransparentScenePhase( ScriptableRenderContext context) { return RecordScenePhaseInternal( context, RecordedScenePhase.Transparent); } protected bool RecordBeforeOpaqueInjection( ScriptableRenderContext context) { return RecordSceneInjectionPointInternal( context, RecordedSceneInjectionPoint.BeforeOpaque); } protected bool RecordAfterOpaqueInjection( ScriptableRenderContext context) { return RecordSceneInjectionPointInternal( context, RecordedSceneInjectionPoint.AfterOpaque); } protected bool RecordBeforeSkyboxInjection( ScriptableRenderContext context) { return RecordSceneInjectionPointInternal( context, RecordedSceneInjectionPoint.BeforeSkybox); } protected bool RecordAfterSkyboxInjection( ScriptableRenderContext context) { return RecordSceneInjectionPointInternal( context, RecordedSceneInjectionPoint.AfterSkybox); } protected bool RecordBeforeTransparentInjection( ScriptableRenderContext context) { return RecordSceneInjectionPointInternal( context, RecordedSceneInjectionPoint.BeforeTransparent); } protected bool RecordAfterTransparentInjection( ScriptableRenderContext context) { return RecordSceneInjectionPointInternal( context, RecordedSceneInjectionPoint.AfterTransparent); } protected bool RecordColorScaleFullscreenPass( ScriptableRenderContext context, Vector4 colorScale) { return RecordFullscreenPassInternal( context, RecordedFullscreenPassType.ColorScale, string.Empty, string.Empty, colorScale); } protected bool RecordShaderVectorFullscreenPass( ScriptableRenderContext context, string shaderPath, Vector4 vectorPayload, string passName = null) { if (string.IsNullOrEmpty(shaderPath)) { throw new ArgumentException( "Fullscreen shader path cannot be null or empty.", nameof(shaderPath)); } return RecordFullscreenPassInternal( context, RecordedFullscreenPassType.ShaderVector, shaderPath, passName ?? string.Empty, vectorPayload); } internal static bool TryResolveStage( RenderPassEvent passEvent, out CameraFrameStage stage) { switch (passEvent) { case RenderPassEvent.BeforeRenderingOpaques: case RenderPassEvent.RenderOpaques: case RenderPassEvent.AfterRenderingOpaques: case RenderPassEvent.BeforeRenderingSkybox: case RenderPassEvent.RenderSkybox: case RenderPassEvent.AfterRenderingSkybox: case RenderPassEvent.BeforeRenderingTransparents: case RenderPassEvent.RenderTransparents: case RenderPassEvent.AfterRenderingTransparents: stage = CameraFrameStage.MainScene; return true; case RenderPassEvent.BeforeRenderingPostProcessing: case RenderPassEvent.AfterRenderingPostProcessing: stage = CameraFrameStage.PostProcess; return true; case RenderPassEvent.BeforeRenderingFinalOutput: case RenderPassEvent.AfterRenderingFinalOutput: stage = CameraFrameStage.FinalOutput; return true; default: stage = CameraFrameStage.MainScene; return false; } } private bool RecordScenePhaseInternal( ScriptableRenderContext context, RecordedScenePhase scenePhase) { return context != null && InternalCalls .Rendering_ScriptableRenderContext_RecordScenePhase( context.nativeHandle, (int)scenePhase); } private bool RecordSceneInjectionPointInternal( ScriptableRenderContext context, RecordedSceneInjectionPoint injectionPoint) { return context != null && InternalCalls .Rendering_ScriptableRenderContext_RecordSceneInjectionPoint( context.nativeHandle, (int)injectionPoint); } private bool RecordFullscreenPassInternal( ScriptableRenderContext context, RecordedFullscreenPassType passType, string shaderPath, string passName, Vector4 vectorPayload) { return context != null && InternalCalls .Rendering_ScriptableRenderContext_RecordFullscreenPass( context.nativeHandle, (int)passType, shaderPath, passName, ref vectorPayload); } } }