using UnityEditor.ShaderGraph; using UnityEngine; using System; using UnityEditor.ShaderGraph.Internal; using System.Linq; using BlendMode = UnityEngine.Rendering.BlendMode; using BlendOp = UnityEditor.ShaderGraph.BlendOp; using UnityEngine.UIElements; using UnityEditor.UIElements; using UnityEngine.Rendering; namespace UnityEditor.Rendering.Fullscreen.ShaderGraph { [GenerateBlocks("Fullscreen")] internal struct FullscreenBlocks { public static BlockFieldDescriptor color = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenColor", "Color", "SURFACEDESCRIPTION_COLOR", new ColorControl(UnityEngine.Color.grey, true), ShaderStage.Fragment); public static BlockFieldDescriptor eyeDepth = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenEyeDepth", "Eye Depth", "SURFACEDESCRIPTION_EYE_DEPTH", new FloatControl(0), ShaderStage.Fragment); public static BlockFieldDescriptor linear01Depth = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenLinear01Depth", "Linear01 Depth", "SURFACEDESCRIPTION_LINEAR01_DEPTH", new FloatControl(0), ShaderStage.Fragment); public static BlockFieldDescriptor rawDepth = new BlockFieldDescriptor(BlockFields.SurfaceDescription.name, "FullscreenRawDepth", "Raw Depth", "SURFACEDESCRIPTION_RAW_DEPTH", new FloatControl(0), ShaderStage.Fragment); } [GenerationAPI] internal struct FullscreenFields { public static FieldDescriptor depth = new FieldDescriptor("OUTPUT", "depth", "OUTPUT_DEPTH"); } internal enum FullscreenMode { FullScreen, CustomRenderTexture, } internal enum FullscreenCompatibility { Blit, DrawProcedural, } internal enum FullscreenBlendMode { Disabled, Alpha, Premultiply, Additive, Multiply, Custom, } internal enum FullscreenDepthWriteMode { LinearEye, Linear01, Raw, } internal static class FullscreenUniforms { public static readonly string blendModeProperty = "_Fullscreen_BlendMode"; public static readonly string srcColorBlendProperty = "_Fullscreen_SrcColorBlend"; public static readonly string dstColorBlendProperty = "_Fullscreen_DstColorBlend"; public static readonly string srcAlphaBlendProperty = "_Fullscreen_SrcAlphaBlend"; public static readonly string dstAlphaBlendProperty = "_Fullscreen_DstAlphaBlend"; public static readonly string colorBlendOperationProperty = "_Fullscreen_ColorBlendOperation"; public static readonly string alphaBlendOperationProperty = "_Fullscreen_AlphaBlendOperation"; public static readonly string depthWriteProperty = "_Fullscreen_DepthWrite"; public static readonly string depthTestProperty = "_Fullscreen_DepthTest"; public static readonly string stencilEnableProperty = "_Fullscreen_Stencil"; public static readonly string stencilReferenceProperty = "_Fullscreen_StencilReference"; public static readonly string stencilReadMaskProperty = "_Fullscreen_StencilReadMask"; public static readonly string stencilWriteMaskProperty = "_Fullscreen_StencilWriteMask"; public static readonly string stencilComparisonProperty = "_Fullscreen_StencilComparison"; public static readonly string stencilPassProperty = "_Fullscreen_StencilPass"; public static readonly string stencilFailProperty = "_Fullscreen_StencilFail"; public static readonly string stencilDepthFailProperty = "_Fullscreen_StencilDepthFail"; public static readonly string srcColorBlend = "[" + srcColorBlendProperty + "]"; public static readonly string dstColorBlend = "[" + dstColorBlendProperty + "]"; public static readonly string srcAlphaBlend = "[" + srcAlphaBlendProperty + "]"; public static readonly string dstAlphaBlend = "[" + dstAlphaBlendProperty + "]"; public static readonly string colorBlendOperation = "[" + colorBlendOperationProperty + "]"; public static readonly string alphaBlendOperation = "[" + alphaBlendOperationProperty + "]"; public static readonly string depthWrite = "[" + depthWriteProperty + "]"; public static readonly string depthTest = "[" + depthTestProperty + "]"; public static readonly string stencilReference = "[" + stencilReferenceProperty + "]"; public static readonly string stencilReadMask = "[" + stencilReadMaskProperty + "]"; public static readonly string stencilWriteMask = "[" + stencilWriteMaskProperty + "]"; public static readonly string stencilComparison = "[" + stencilComparisonProperty + "]"; public static readonly string stencilPass = "[" + stencilPassProperty + "]"; public static readonly string stencilFail = "[" + stencilFailProperty + "]"; public static readonly string stencilDepthFail = "[" + stencilDepthFailProperty + "]"; } internal abstract class FullscreenSubTarget : SubTarget, IRequiresData, IHasMetadata where T : Target { static readonly GUID kSourceCodeGuid = new GUID("1cfc804c75474e144be5d4158b9522ed"); // FullscreenSubTarget.cs // TODO static readonly string[] kSharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories().Union(new string[] { "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Templates" }).ToArray(); // HLSL includes protected static readonly string kFullscreenCommon = "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenCommon.hlsl"; protected static readonly string kTemplatePath = "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Templates/ShaderPass.template"; protected static readonly string kCommon = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"; protected static readonly string kColor = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"; protected static readonly string kTexture = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"; protected static readonly string kInstancing = "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"; protected static readonly string kFullscreenShaderPass = "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenShaderPass.cs.hlsl"; protected static readonly string kSpaceTransforms = "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"; protected static readonly string kFunctions = "Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl"; protected static readonly string kTextureStack = "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"; protected virtual string fullscreenDrawProceduralInclude => "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenDrawProcedural.hlsl"; protected virtual string fullscreenBlitInclude => "Packages/com.unity.shadergraph/Editor/Generation/Targets/Fullscreen/Includes/FullscreenBlit.hlsl"; FullscreenData m_FullscreenData; FullscreenData IRequiresData.data { get => m_FullscreenData; set => m_FullscreenData = value; } public FullscreenData fullscreenData { get => m_FullscreenData; set => m_FullscreenData = value; } public override void Setup(ref TargetSetupContext context) { context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency); context.SetDefaultShaderGUI(GetDefaultShaderGUI().FullName); context.AddSubShader(GenerateSubShader()); } protected virtual IncludeCollection pregraphIncludes => new IncludeCollection(); protected abstract string pipelineTag { get; } protected virtual Type GetDefaultShaderGUI() => typeof(FullscreenShaderGUI); public virtual string identifier => GetType().Name; public virtual ScriptableObject GetMetadataObject(GraphDataReadOnly graph) { var bultInMetadata = ScriptableObject.CreateInstance(); bultInMetadata.fullscreenMode = fullscreenData.fullscreenMode; return bultInMetadata; } public RenderStateCollection GetRenderState() { var result = new RenderStateCollection(); if (fullscreenData.allowMaterialOverride) { if (fullscreenData.depthTestMode != CompareFunction.Disabled) result.Add(RenderState.ZTest(FullscreenUniforms.depthTest)); else result.Add(RenderState.ZTest("Off")); result.Add(RenderState.ZWrite(FullscreenUniforms.depthWrite)); if (fullscreenData.blendMode != FullscreenBlendMode.Disabled) { result.Add(RenderState.Blend(FullscreenUniforms.srcColorBlend, FullscreenUniforms.dstColorBlend, FullscreenUniforms.srcAlphaBlend, FullscreenUniforms.dstAlphaBlend)); result.Add(RenderState.BlendOp(FullscreenUniforms.colorBlendOperation, FullscreenUniforms.alphaBlendOperation)); } else { result.Add(RenderState.Blend("Blend Off")); } if (fullscreenData.enableStencil) { result.Add(RenderState.Stencil(new StencilDescriptor { Ref = FullscreenUniforms.stencilReference, ReadMask = FullscreenUniforms.stencilReadMask, WriteMask = FullscreenUniforms.stencilWriteMask, Comp = FullscreenUniforms.stencilComparison, ZFail = FullscreenUniforms.stencilDepthFail, Fail = FullscreenUniforms.stencilFail, Pass = FullscreenUniforms.stencilPass })); } } else { if (fullscreenData.depthTestMode == CompareFunction.Disabled) result.Add(RenderState.ZTest("Off")); else result.Add(RenderState.ZTest(CompareFunctionToZTest(fullscreenData.depthTestMode).ToString())); result.Add(RenderState.ZWrite(fullscreenData.depthWrite ? ZWrite.On.ToString() : ZWrite.Off.ToString())); // Blend mode if (fullscreenData.blendMode == FullscreenBlendMode.Alpha) result.Add(RenderState.Blend(Blend.SrcAlpha, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha)); else if (fullscreenData.blendMode == FullscreenBlendMode.Premultiply) result.Add(RenderState.Blend(Blend.One, Blend.OneMinusSrcAlpha, Blend.One, Blend.OneMinusSrcAlpha)); else if (fullscreenData.blendMode == FullscreenBlendMode.Additive) result.Add(RenderState.Blend(Blend.SrcAlpha, Blend.One, Blend.One, Blend.One)); else if (fullscreenData.blendMode == FullscreenBlendMode.Multiply) result.Add(RenderState.Blend(Blend.DstColor, Blend.Zero)); else if (fullscreenData.blendMode == FullscreenBlendMode.Disabled) result.Add(RenderState.Blend("Blend Off")); else { result.Add(RenderState.Blend(BlendModeToBlend(fullscreenData.srcColorBlendMode), BlendModeToBlend(fullscreenData.dstColorBlendMode), BlendModeToBlend(fullscreenData.srcAlphaBlendMode), BlendModeToBlend(fullscreenData.dstAlphaBlendMode))); result.Add(RenderState.BlendOp(fullscreenData.colorBlendOperation, fullscreenData.alphaBlendOperation)); } if (fullscreenData.enableStencil) { result.Add(RenderState.Stencil(new StencilDescriptor { Ref = fullscreenData.stencilReference.ToString(), ReadMask = fullscreenData.stencilReadMask.ToString(), WriteMask = fullscreenData.stencilWriteMask.ToString(), Comp = CompareFunctionToStencilString(fullscreenData.stencilCompareFunction), ZFail = StencilOpToStencilString(fullscreenData.stencilDepthTestFailOperation), Fail = StencilOpToStencilString(fullscreenData.stencilFailOperation), Pass = StencilOpToStencilString(fullscreenData.stencilPassOperation), })); } } result.Add(RenderState.Cull(UnityEditor.ShaderGraph.Cull.Off)); return result; } public static Blend BlendModeToBlend(BlendMode mode) { switch (mode) { case BlendMode.Zero: return Blend.Zero; case BlendMode.One: return Blend.One; case BlendMode.DstColor: return Blend.DstColor; case BlendMode.SrcColor: return Blend.SrcColor; case BlendMode.OneMinusDstColor: return Blend.OneMinusDstColor; case BlendMode.SrcAlpha: return Blend.SrcAlpha; case BlendMode.OneMinusSrcColor: return Blend.OneMinusSrcColor; case BlendMode.DstAlpha: return Blend.DstAlpha; case BlendMode.OneMinusDstAlpha: return Blend.OneMinusDstAlpha; case BlendMode.SrcAlphaSaturate: return Blend.SrcAlpha; case BlendMode.OneMinusSrcAlpha: return Blend.OneMinusSrcAlpha; default: return Blend.Zero; } ; } public static ZTest CompareFunctionToZTest(CompareFunction mode) { switch (mode) { case CompareFunction.Equal: return ZTest.Equal; case CompareFunction.NotEqual: return ZTest.NotEqual; case CompareFunction.Greater: return ZTest.Greater; case CompareFunction.Less: return ZTest.Less; case CompareFunction.GreaterEqual: return ZTest.GEqual; case CompareFunction.LessEqual: return ZTest.LEqual; case CompareFunction.Always: return ZTest.Always; case CompareFunction.Disabled: return ZTest.Always; default: return ZTest.Always; } ; } public static string CompareFunctionToStencilString(CompareFunction compare) { switch (compare) { case CompareFunction.Never: return "Never"; case CompareFunction.Equal: return "Equal"; case CompareFunction.NotEqual: return "NotEqual"; case CompareFunction.Greater: return "Greater"; case CompareFunction.Less: return "Less"; case CompareFunction.GreaterEqual: return "GEqual"; case CompareFunction.LessEqual: return "LEqual"; case CompareFunction.Always: return "Always"; default: return "Always"; } ; } public static string StencilOpToStencilString(StencilOp op) { switch (op) { case StencilOp.Keep: return "Keep"; case StencilOp.Zero: return "Zero"; case StencilOp.Replace: return "Replace"; case StencilOp.IncrementSaturate: return "IncrSat"; case StencilOp.DecrementSaturate: return "DecrSat"; case StencilOp.Invert: return "Invert"; case StencilOp.IncrementWrap: return "IncrWrap"; case StencilOp.DecrementWrap: return "DecrWrap"; default: return "Keep"; } ; } public virtual SubShaderDescriptor GenerateSubShader() { var result = new SubShaderDescriptor() { generatesPreview = true, passes = new PassCollection(), pipelineTag = pipelineTag, }; result.passes.Add(GenerateFullscreenPass(FullscreenCompatibility.DrawProcedural)); result.passes.Add(GenerateFullscreenPass(FullscreenCompatibility.Blit)); return result; } public virtual IncludeCollection GetPreGraphIncludes() { return new IncludeCollection { { kCommon, IncludeLocation.Pregraph }, { kColor, IncludeLocation.Pregraph }, { kTexture, IncludeLocation.Pregraph }, { kTextureStack, IncludeLocation.Pregraph }, { kFullscreenShaderPass, IncludeLocation.Pregraph }, // For VR { pregraphIncludes }, { kSpaceTransforms, IncludeLocation.Pregraph }, { kFunctions, IncludeLocation.Pregraph }, }; } public virtual IncludeCollection GetPostGraphIncludes() { return new IncludeCollection { { kFullscreenCommon, IncludeLocation.Postgraph } }; } static readonly KeywordDescriptor depthWriteKeyword = new KeywordDescriptor { displayName = "Depth Write", referenceName = "DEPTH_WRITE", type = KeywordType.Boolean, definition = KeywordDefinition.ShaderFeature, stages = KeywordShaderStage.Fragment, }; static readonly KeywordDescriptor depthWriteModeKeyword = new KeywordDescriptor { displayName = "Depth Write Mode", referenceName = "DEPTH_WRITE_MODE", type = KeywordType.Enum, definition = KeywordDefinition.Predefined, entries = new KeywordEntry[] { new KeywordEntry("Eye Depth", "EYE"), new KeywordEntry("Eye Linear 01", "LINEAR01"), new KeywordEntry("Eye Raw", "RAW"), }, stages = KeywordShaderStage.Fragment, }; public static StructDescriptor Varyings = new StructDescriptor() { name = "Varyings", packFields = true, populateWithCustomInterpolators = false, fields = new FieldDescriptor[] { StructFields.Varyings.positionCS, StructFields.Varyings.texCoord0, StructFields.Varyings.texCoord1, StructFields.Varyings.instanceID, StructFields.Varyings.stereoTargetEyeIndexAsBlendIdx0, StructFields.Varyings.stereoTargetEyeIndexAsRTArrayIdx, } }; protected virtual DefineCollection GetPassDefines(FullscreenCompatibility compatibility) => new DefineCollection(); protected virtual KeywordCollection GetPassKeywords(FullscreenCompatibility compatibility) => new KeywordCollection(); static StructDescriptor GetFullscreenAttributes(FullscreenCompatibility compatibility) { var desc = new StructDescriptor() { name = "Attributes", packFields = false, }; if (compatibility == FullscreenCompatibility.Blit) { desc.fields = new FieldDescriptor[] { StructFields.Attributes.instanceID, StructFields.Attributes.vertexID, StructFields.Attributes.positionOS, }; } else { desc.fields = new FieldDescriptor[] { StructFields.Attributes.instanceID, StructFields.Attributes.vertexID, }; } return desc; } public virtual PassDescriptor GenerateFullscreenPass(FullscreenCompatibility compatibility) { var fullscreenPass = new PassDescriptor { // Definition displayName = compatibility.ToString(), referenceName = "SHADERPASS_" + compatibility.ToString().ToUpper(), useInPreview = true, // Template passTemplatePath = kTemplatePath, sharedTemplateDirectories = kSharedTemplateDirectories, // Port Mask validVertexBlocks = null, validPixelBlocks = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.Alpha, FullscreenBlocks.eyeDepth, FullscreenBlocks.linear01Depth, FullscreenBlocks.rawDepth, }, // Fields structs = new StructCollection { { GetFullscreenAttributes(compatibility) }, { Structs.SurfaceDescriptionInputs }, { Varyings }, { Structs.VertexDescriptionInputs }, }, fieldDependencies = FieldDependencies.Default, requiredFields = new FieldCollection { StructFields.Varyings.texCoord0, // Always need texCoord0 to calculate the other properties in fullscreen node code StructFields.Varyings.texCoord1, // We store the view direction computed in the vertex in the texCoord1 StructFields.Attributes.vertexID, // Need the vertex Id for the DrawProcedural case }, // Conditional State renderStates = GetRenderState(), pragmas = new PragmaCollection { { Pragma.Target(ShaderModel.Target30) }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") }, }, defines = new DefineCollection { {depthWriteKeyword, 1, new FieldCondition(FullscreenFields.depth, true)}, {depthWriteModeKeyword, (int)fullscreenData.depthWriteMode, new FieldCondition(FullscreenFields.depth, true)}, GetPassDefines(compatibility), }, keywords = GetPassKeywords(compatibility), includes = new IncludeCollection { // Pre-graph GetPreGraphIncludes(), // Post-graph GetPostGraphIncludes(), }, }; switch (compatibility) { default: case FullscreenCompatibility.Blit: fullscreenPass.includes.Add(fullscreenBlitInclude, IncludeLocation.Postgraph); break; case FullscreenCompatibility.DrawProcedural: fullscreenPass.includes.Add(fullscreenDrawProceduralInclude, IncludeLocation.Postgraph); break; } return fullscreenPass; } // We don't need the save context / update materials for now public override object saveContext => null; public FullscreenSubTarget() { displayName = "Fullscreen"; } public override bool IsNodeAllowedBySubTarget(Type nodeType) { var interfaces = nodeType.GetInterfaces(); bool allowed = true; // Subgraph nodes inherits all the interfaces including vertex ones. if (nodeType == typeof(SubGraphNode)) return true; // There is no input in the vertex block for now if (interfaces.Contains(typeof(IMayRequireVertexID)) || interfaces.Contains(typeof(IMayRequireVertexSkinning)) || interfaces.Contains(typeof(IMayRequireInstanceID))) allowed = false; return allowed; } public override bool IsActive() => true; public override void GetFields(ref TargetFieldContext context) { context.AddField(UnityEditor.ShaderGraph.Fields.GraphPixel); context.AddField(FullscreenFields.depth, fullscreenData.depthWrite || fullscreenData.depthTestMode != CompareFunction.Disabled); } public override void GetActiveBlocks(ref TargetActiveBlockContext context) { context.AddBlock(BlockFields.SurfaceDescription.BaseColor); context.AddBlock(BlockFields.SurfaceDescription.Alpha); var depthBlock = FullscreenBlocks.eyeDepth; if (fullscreenData.depthWriteMode == FullscreenDepthWriteMode.Linear01) depthBlock = FullscreenBlocks.linear01Depth; if (fullscreenData.depthWriteMode == FullscreenDepthWriteMode.Raw) depthBlock = FullscreenBlocks.rawDepth; context.AddBlock(depthBlock, fullscreenData.depthWrite || fullscreenData.depthTestMode != CompareFunction.Disabled); } public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode) { if (fullscreenData.allowMaterialOverride) { base.CollectShaderProperties(collector, generationMode); CollectRenderStateShaderProperties(collector, generationMode); } collector.AddFloatProperty("_FlipY", 0, HLSLDeclaration.Global, false); } public void CollectRenderStateShaderProperties(PropertyCollector collector, GenerationMode generationMode) { if (generationMode != GenerationMode.Preview && fullscreenData.allowMaterialOverride) { // When blend mode is disabled, we can't override if (fullscreenData.blendMode != FullscreenBlendMode.Disabled) { BlendMode srcColorBlend = fullscreenData.srcColorBlendMode; BlendMode srcAlphaBlend = fullscreenData.srcAlphaBlendMode; BlendMode dstColorBlend = fullscreenData.dstColorBlendMode; BlendMode dstAlphaBlend = fullscreenData.dstAlphaBlendMode; BlendOp colorBlendOp = fullscreenData.colorBlendOperation; BlendOp alphaBlendOp = fullscreenData.alphaBlendOperation; // Patch the default blend values depending on the Blend Mode: if (fullscreenData.blendMode != FullscreenBlendMode.Custom) { colorBlendOp = BlendOp.Add; alphaBlendOp = BlendOp.Add; } if (fullscreenData.blendMode == FullscreenBlendMode.Alpha) { srcColorBlend = BlendMode.SrcAlpha; dstColorBlend = BlendMode.OneMinusSrcAlpha; srcAlphaBlend = BlendMode.One; dstAlphaBlend = BlendMode.OneMinusSrcAlpha; } else if (fullscreenData.blendMode == FullscreenBlendMode.Premultiply) { srcColorBlend = BlendMode.One; dstColorBlend = BlendMode.OneMinusSrcAlpha; srcAlphaBlend = BlendMode.One; dstAlphaBlend = BlendMode.OneMinusSrcAlpha; } else if (fullscreenData.blendMode == FullscreenBlendMode.Additive) { srcColorBlend = BlendMode.SrcAlpha; dstColorBlend = BlendMode.One; srcAlphaBlend = BlendMode.One; dstAlphaBlend = BlendMode.One; } else if (fullscreenData.blendMode == FullscreenBlendMode.Multiply) { srcColorBlend = BlendMode.DstColor; dstColorBlend = BlendMode.Zero; srcAlphaBlend = BlendMode.One; dstAlphaBlend = BlendMode.OneMinusSrcAlpha; } collector.AddEnumProperty(FullscreenUniforms.blendModeProperty, fullscreenData.blendMode); collector.AddEnumProperty(FullscreenUniforms.srcColorBlendProperty, srcColorBlend); collector.AddEnumProperty(FullscreenUniforms.dstColorBlendProperty, dstColorBlend); collector.AddEnumProperty(FullscreenUniforms.srcAlphaBlendProperty, srcAlphaBlend); collector.AddEnumProperty(FullscreenUniforms.dstAlphaBlendProperty, dstAlphaBlend); collector.AddEnumProperty(FullscreenUniforms.colorBlendOperationProperty, colorBlendOp); collector.AddEnumProperty(FullscreenUniforms.alphaBlendOperationProperty, alphaBlendOp); } collector.AddBoolProperty(FullscreenUniforms.depthWriteProperty, fullscreenData.depthWrite); if (fullscreenData.depthTestMode != CompareFunction.Disabled) collector.AddEnumProperty(FullscreenUniforms.depthTestProperty, fullscreenData.depthTestMode); // When stencil is disabled, we can't override if (fullscreenData.enableStencil) { collector.AddBoolProperty(FullscreenUniforms.stencilEnableProperty, fullscreenData.enableStencil); collector.AddIntProperty(FullscreenUniforms.stencilReferenceProperty, fullscreenData.stencilReference); collector.AddIntProperty(FullscreenUniforms.stencilReadMaskProperty, fullscreenData.stencilReadMask); collector.AddIntProperty(FullscreenUniforms.stencilWriteMaskProperty, fullscreenData.stencilWriteMask); collector.AddEnumProperty(FullscreenUniforms.stencilComparisonProperty, fullscreenData.stencilCompareFunction); collector.AddEnumProperty(FullscreenUniforms.stencilPassProperty, fullscreenData.stencilPassOperation); collector.AddEnumProperty(FullscreenUniforms.stencilFailProperty, fullscreenData.stencilFailOperation); collector.AddEnumProperty(FullscreenUniforms.stencilDepthFailProperty, fullscreenData.stencilDepthTestFailOperation); } } } public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { context.AddProperty("Allow Material Override", new Toggle() { value = fullscreenData.allowMaterialOverride }, (evt) => { if (Equals(fullscreenData.allowMaterialOverride, evt.newValue)) return; registerUndo("Change Allow Material Override"); fullscreenData.allowMaterialOverride = evt.newValue; onChange(); }); GetRenderStatePropertiesGUI(ref context, onChange, registerUndo); } protected virtual void GetRenderStatePropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { GetBlendingPropertiesGUI(ref context, onChange, registerUndo); context.AddProperty("Depth Test", new EnumField(fullscreenData.depthTestMode) { value = fullscreenData.depthTestMode }, (evt) => { if (Equals(fullscreenData.depthTestMode, evt.newValue)) return; registerUndo("Change Depth Test"); fullscreenData.depthTestMode = (CompareFunction)evt.newValue; onChange(); }); context.AddProperty("Depth Write", new Toggle { value = fullscreenData.depthWrite }, (evt) => { if (Equals(fullscreenData.depthWrite, evt.newValue)) return; registerUndo("Change Depth Write"); fullscreenData.depthWrite = evt.newValue; onChange(); }); if (fullscreenData.depthWrite || fullscreenData.depthTestMode != CompareFunction.Disabled) { context.AddProperty("Depth Write Mode", new EnumField(fullscreenData.depthWriteMode) { value = fullscreenData.depthWriteMode }, (evt) => { if (Equals(fullscreenData.depthWriteMode, evt.newValue)) return; registerUndo("Change Depth Write Mode"); fullscreenData.depthWriteMode = (FullscreenDepthWriteMode)evt.newValue; onChange(); }); } GetStencilPropertiesGUI(ref context, onChange, registerUndo); } protected virtual void GetBlendingPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { context.AddProperty("Blend Mode", new EnumField(fullscreenData.blendMode) { value = fullscreenData.blendMode }, (evt) => { if (Equals(fullscreenData.blendMode, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.blendMode = (FullscreenBlendMode)evt.newValue; onChange(); }); if (fullscreenData.blendMode == FullscreenBlendMode.Custom) { context.globalIndentLevel++; context.AddLabel("Color Blend Mode", 0); context.AddProperty("Src Color", new EnumField(fullscreenData.srcColorBlendMode) { value = fullscreenData.srcColorBlendMode }, (evt) => { if (Equals(fullscreenData.srcColorBlendMode, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.srcColorBlendMode = (BlendMode)evt.newValue; onChange(); }); context.AddProperty("Dst Color", new EnumField(fullscreenData.dstColorBlendMode) { value = fullscreenData.dstColorBlendMode }, (evt) => { if (Equals(fullscreenData.dstColorBlendMode, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.dstColorBlendMode = (BlendMode)evt.newValue; onChange(); }); context.AddProperty("Color Operation", new EnumField(fullscreenData.colorBlendOperation) { value = fullscreenData.colorBlendOperation }, (evt) => { if (Equals(fullscreenData.colorBlendOperation, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.colorBlendOperation = (BlendOp)evt.newValue; onChange(); }); context.AddLabel("Alpha Blend Mode", 0); context.AddProperty("Src", new EnumField(fullscreenData.srcAlphaBlendMode) { value = fullscreenData.srcAlphaBlendMode }, (evt) => { if (Equals(fullscreenData.srcAlphaBlendMode, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.srcAlphaBlendMode = (BlendMode)evt.newValue; onChange(); }); context.AddProperty("Dst", new EnumField(fullscreenData.dstAlphaBlendMode) { value = fullscreenData.dstAlphaBlendMode }, (evt) => { if (Equals(fullscreenData.dstAlphaBlendMode, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.dstAlphaBlendMode = (BlendMode)evt.newValue; onChange(); }); context.AddProperty("Blend Operation Alpha", new EnumField(fullscreenData.alphaBlendOperation) { value = fullscreenData.alphaBlendOperation }, (evt) => { if (Equals(fullscreenData.alphaBlendOperation, evt.newValue)) return; registerUndo("Change Blend Mode"); fullscreenData.alphaBlendOperation = (BlendOp)evt.newValue; onChange(); }); context.globalIndentLevel--; } } protected virtual void GetStencilPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { context.AddProperty("Enable Stencil", new Toggle { value = fullscreenData.enableStencil }, (evt) => { if (Equals(fullscreenData.enableStencil, evt.newValue)) return; registerUndo("Change Enable Stencil"); fullscreenData.enableStencil = evt.newValue; onChange(); }); if (fullscreenData.enableStencil) { context.globalIndentLevel++; context.AddProperty("Reference", new IntegerField { value = fullscreenData.stencilReference, isDelayed = true }, (evt) => { if (Equals(fullscreenData.stencilReference, evt.newValue)) return; registerUndo("Change Stencil Reference"); fullscreenData.stencilReference = evt.newValue; onChange(); }); context.AddProperty("Read Mask", new IntegerField { value = fullscreenData.stencilReadMask, isDelayed = true }, (evt) => { if (Equals(fullscreenData.stencilReadMask, evt.newValue)) return; registerUndo("Change Stencil Read Mask"); fullscreenData.stencilReadMask = evt.newValue; onChange(); }); context.AddProperty("Write Mask", new IntegerField { value = fullscreenData.stencilWriteMask, isDelayed = true }, (evt) => { if (Equals(fullscreenData.stencilWriteMask, evt.newValue)) return; registerUndo("Change Stencil Write Mask"); fullscreenData.stencilWriteMask = evt.newValue; onChange(); }); context.AddProperty("Comparison", new EnumField(fullscreenData.stencilCompareFunction) { value = fullscreenData.stencilCompareFunction }, (evt) => { if (Equals(fullscreenData.stencilCompareFunction, evt.newValue)) return; registerUndo("Change Stencil Comparison"); fullscreenData.stencilCompareFunction = (CompareFunction)evt.newValue; onChange(); }); context.AddProperty("Pass", new EnumField(fullscreenData.stencilPassOperation) { value = fullscreenData.stencilPassOperation }, (evt) => { if (Equals(fullscreenData.stencilPassOperation, evt.newValue)) return; registerUndo("Change Stencil Pass Operation"); fullscreenData.stencilPassOperation = (StencilOp)evt.newValue; onChange(); }); context.AddProperty("Fail", new EnumField(fullscreenData.stencilFailOperation) { value = fullscreenData.stencilFailOperation }, (evt) => { if (Equals(fullscreenData.stencilFailOperation, evt.newValue)) return; registerUndo("Change Stencil Fail Operation"); fullscreenData.stencilFailOperation = (StencilOp)evt.newValue; onChange(); }); context.AddProperty("Depth Fail", new EnumField(fullscreenData.stencilDepthTestFailOperation) { value = fullscreenData.stencilDepthTestFailOperation }, (evt) => { if (Equals(fullscreenData.stencilDepthTestFailOperation, evt.newValue)) return; registerUndo("Change Stencil Depth Fail Operation"); fullscreenData.stencilDepthTestFailOperation = (StencilOp)evt.newValue; onChange(); }); context.globalIndentLevel--; } } } internal static class FullscreenPropertyCollectorExtension { public static void AddEnumProperty(this PropertyCollector collector, string prop, T value, HLSLDeclaration hlslDeclaration = HLSLDeclaration.DoNotDeclare) where T : Enum { collector.AddShaderProperty(new Vector1ShaderProperty { floatType = FloatType.Enum, enumType = EnumType.CSharpEnum, cSharpEnumType = typeof(T), hidden = true, overrideHLSLDeclaration = true, hlslDeclarationOverride = hlslDeclaration, value = Convert.ToInt32(value), overrideReferenceName = prop, }); } public static void AddIntProperty(this PropertyCollector collector, string prop, int value, HLSLDeclaration hlslDeclaration = HLSLDeclaration.DoNotDeclare) { collector.AddShaderProperty(new Vector1ShaderProperty { floatType = FloatType.Integer, hidden = true, overrideHLSLDeclaration = true, hlslDeclarationOverride = hlslDeclaration, value = value, overrideReferenceName = prop, }); } public static void AddBoolProperty(this PropertyCollector collector, string prop, bool value, HLSLDeclaration hlslDeclaration = HLSLDeclaration.DoNotDeclare) { collector.AddShaderProperty(new BooleanShaderProperty { hidden = true, overrideHLSLDeclaration = true, hlslDeclarationOverride = hlslDeclaration, value = value, overrideReferenceName = prop, }); } public static void AddFloatProperty(this PropertyCollector collector, string referenceName, float defaultValue, HLSLDeclaration declarationType = HLSLDeclaration.DoNotDeclare, bool generatePropertyBlock = true) { collector.AddShaderProperty(new Vector1ShaderProperty { floatType = FloatType.Default, hidden = true, overrideHLSLDeclaration = true, hlslDeclarationOverride = declarationType, value = defaultValue, generatePropertyBlock = generatePropertyBlock, overrideReferenceName = referenceName, }); } } }