using XCEngine; using XCEngine.Rendering; namespace XCEngine.Rendering.Universal { public abstract class ScriptableRendererFeature : Object { private bool m_disposed; private bool m_runtimeCreated; private bool m_isActive = true; private int m_runtimeStateVersion = 1; private int m_runtimeStateHash; private bool m_runtimeStateHashResolved; private ScriptableRendererData m_owner; protected ScriptableRendererFeature() { } public bool isActive { get { return m_isActive; } set { if (m_isActive == value) { return; } m_isActive = value; SetDirty(); } } internal void BindOwnerInstance( ScriptableRendererData owner) { m_owner = owner; } internal int GetRuntimeStateVersionInstance() { SynchronizeRuntimeStateVersion(); return m_runtimeStateVersion; } internal void CreateInstance() { if (m_runtimeCreated) { return; } m_disposed = false; Create(); m_runtimeCreated = true; } internal void ReleaseRuntimeResourcesInstance() { if (m_disposed || !m_runtimeCreated) { return; } ReleaseRuntimeResources(); m_disposed = true; m_runtimeCreated = false; } public virtual void Create() { } public virtual void ConfigureCameraRenderRequest( CameraRenderRequestContext context) { } public virtual void ConfigureCameraFramePlan( ScriptableRenderPipelinePlanningContext context) { } public virtual void ConfigureRenderSceneSetup( RenderSceneSetupContext context) { } public virtual void ConfigureDirectionalShadowExecutionState( DirectionalShadowExecutionContext context) { } public virtual void AddRenderPasses( ScriptableRenderer renderer, RenderingData renderingData) { } protected bool HasDirectionalShadow( CameraRenderRequestContext context) { return context != null && InternalCalls .Rendering_CameraRenderRequestContext_GetHasDirectionalShadow( context.nativeHandle); } protected void ClearDirectionalShadow( CameraRenderRequestContext context) { if (context == null) { return; } InternalCalls .Rendering_CameraRenderRequestContext_ClearDirectionalShadow( context.nativeHandle); } protected virtual void ReleaseRuntimeResources() { } protected virtual int ComputeRuntimeStateHash() { int hash = 17; hash = RuntimeStateHashUtility.Combine( hash, m_isActive); return hash; } protected void SetDirty() { ApplyDirty( ComputeRuntimeStateHash()); } private void SynchronizeRuntimeStateVersion() { int runtimeStateHash = ComputeRuntimeStateHash(); if (!m_runtimeStateHashResolved) { m_runtimeStateHash = runtimeStateHash; m_runtimeStateHashResolved = true; return; } if (runtimeStateHash == m_runtimeStateHash) { return; } ApplyDirty(runtimeStateHash); } private void ApplyDirty( int runtimeStateHash) { m_runtimeStateHash = runtimeStateHash; m_runtimeStateHashResolved = true; if (m_runtimeCreated && !m_disposed) { ReleaseRuntimeResources(); } m_disposed = false; m_runtimeCreated = false; unchecked { ++m_runtimeStateVersion; } if (m_runtimeStateVersion <= 0) { m_runtimeStateVersion = 1; } if (m_owner != null) { m_owner.InvalidateRendererFeaturesInstance(); } } } internal static class RuntimeStateHashUtility { public static int Combine( int hash, bool value) { return Combine( hash, value ? 1 : 0); } public static int Combine( int hash, byte value) { return Combine( hash, (int)value); } public static int Combine( int hash, uint value) { unchecked { return (hash * 31) + (int)value; } } public static int Combine( int hash, int value) { unchecked { return (hash * 31) + value; } } public static int Combine( int hash, float value) { return Combine( hash, value.GetHashCode()); } public static int Combine( int hash, string value) { return Combine( hash, value != null ? value.GetHashCode() : 0); } public static int Combine( int hash, Vector4 value) { hash = Combine(hash, value.X); hash = Combine(hash, value.Y); hash = Combine(hash, value.Z); hash = Combine(hash, value.W); return hash; } public static int Combine( int hash, RenderQueueRange value) { hash = Combine(hash, value.lowerBound); hash = Combine(hash, value.upperBound); return hash; } public static int Combine( int hash, FilteringSettings value) { hash = Combine(hash, value.renderQueueMin); hash = Combine(hash, value.renderQueueMax); hash = Combine(hash, value.renderLayerMask); hash = Combine(hash, value.requireShadowCasting); hash = Combine(hash, value.requireRenderObjectId); return hash; } public static int Combine( int hash, SortingSettings value) { return Combine( hash, (int)value.sortMode); } public static int Combine( int hash, RendererListDesc value) { hash = Combine(hash, (int)value.type); hash = Combine(hash, value.filtering); hash = Combine(hash, value.sorting); return hash; } public static int Combine( int hash, DepthState value) { hash = Combine(hash, value.writeEnabled); hash = Combine(hash, (int)value.compareFunction); return hash; } public static int Combine( int hash, StencilFaceState value) { hash = Combine(hash, (int)value.failOperation); hash = Combine(hash, (int)value.passOperation); hash = Combine(hash, (int)value.depthFailOperation); hash = Combine(hash, (int)value.compareFunction); return hash; } public static int Combine( int hash, StencilState value) { hash = Combine(hash, value.enabled); hash = Combine(hash, value.readMask); hash = Combine(hash, value.writeMask); hash = Combine(hash, value.frontFace); hash = Combine(hash, value.backFace); return hash; } public static int Combine( int hash, RenderStateBlock value) { hash = Combine(hash, (int)value.mask); hash = Combine(hash, value.depthState); hash = Combine(hash, value.stencilState); hash = Combine(hash, value.stencilReference); return hash; } public static int Combine( int hash, DrawingSettings value) { hash = Combine(hash, value.overrideMaterialPath); hash = Combine(hash, value.shaderPassName); hash = Combine(hash, value.renderStateBlock); return hash; } } }