private void ProcessIncludeCommand(Token includeCommand, int lineEnd) { if (Expect(includeCommand.s, includeCommand.end, '(')) { Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd); if (!param.IsValid()) { Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1); } else { var includeLocation = Path.Combine(templatePath, param.GetString()); if (!File.Exists(includeLocation)) { Error("ERROR: $include cannot find file : " + includeLocation, includeCommand.s, param.start); } else { int endIndex = result.length; using (var temp = new ShaderStringBuilder()) { // Wrap in debug mode if (isDebug) { result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendNewLine(); } // Recursively process templates ProcessTemplateFile(includeLocation); // Wrap in debug mode if (isDebug) { result.AppendNewLine(); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); } result.AppendNewLine(); // Required to enforce indentation rules // Append lines from this include into temporary StringBuilder // Reduce result length to remove this include temp.AppendLines(result.ToString(endIndex, result.length - endIndex)); result.length = endIndex; result.AppendLines(temp.ToCodeBlock()); } } } } }
public static string ToShaderString(this StencilDescriptor descriptor) { ShaderStringBuilder builder = new ShaderStringBuilder(); builder.AppendLine("Stencil"); using (builder.BlockScope()) { string compBack = descriptor.CompBack != null && descriptor.CompBack.Length > 0 ? descriptor.CompBack : descriptor.Comp; string zFailBack = descriptor.ZFailBack != null && descriptor.ZFailBack.Length > 0 ? descriptor.ZFailBack : descriptor.ZFail; string failBack = descriptor.FailBack != null && descriptor.FailBack.Length > 0 ? descriptor.FailBack : descriptor.Fail; string passBack = descriptor.PassBack != null && descriptor.PassBack.Length > 0 ? descriptor.PassBack : descriptor.Pass; if (descriptor.WriteMask != null && descriptor.WriteMask.Length > 0) { builder.AppendLine($"WriteMask {descriptor.WriteMask}"); } if (descriptor.Ref != null && descriptor.Ref.Length > 0) { builder.AppendLine($"Ref {descriptor.Ref}"); } if (descriptor.Comp != null && descriptor.Comp.Length > 0) { builder.AppendLine($"CompFront {descriptor.Comp}"); } if (descriptor.ZFail != null && descriptor.ZFail.Length > 0) { builder.AppendLine($"ZFailFront {descriptor.ZFail}"); } if (descriptor.Fail != null && descriptor.Fail.Length > 0) { builder.AppendLine($"FailFront {descriptor.Fail}"); } if (descriptor.Pass != null && descriptor.Pass.Length > 0) { builder.AppendLine($"PassFront {descriptor.Pass}"); } if (compBack != null && compBack.Length > 0) { builder.AppendLine($"CompBack {compBack}"); } if (zFailBack != null && zFailBack.Length > 0) { builder.AppendLine($"ZFailBack {zFailBack}"); } if (failBack != null && failBack.Length > 0) { builder.AppendLine($"FailBack {failBack}"); } if (passBack != null && passBack.Length > 0) { builder.AppendLine($"PassBack {passBack}"); } } return(builder.ToCodeBlock()); }
public static string ToShaderString(this StencilDescriptor descriptor) { ShaderStringBuilder builder = new ShaderStringBuilder(); builder.AppendLine("Stencil"); using (builder.BlockScope()) { builder.AppendLine($"WriteMask {descriptor.WriteMask}"); builder.AppendLine($"Ref {descriptor.Ref}"); builder.AppendLine($"Comp {descriptor.Comp}"); builder.AppendLine($"Pass {descriptor.Pass}"); } return(builder.ToCodeBlock()); }
private static bool EquivalentHLSLProperties(AbstractShaderProperty a, AbstractShaderProperty b) { bool equivalent = true; var bHLSLProps = new List <HLSLProperty>(); b.ForeachHLSLProperty(bh => bHLSLProps.Add(bh)); a.ForeachHLSLProperty(ah => { var i = bHLSLProps.FindIndex(bh => bh.name == ah.name); if (i < 0) { equivalent = false; } else { var bh = bHLSLProps[i]; if ((ah.name != bh.name) || (ah.type != bh.type) || (ah.precision != bh.precision) || (ah.declaration != bh.declaration) || ((ah.customDeclaration == null) != (bh.customDeclaration == null))) { equivalent = false; } else if (ah.customDeclaration != null) { var ssba = new ShaderStringBuilder(); var ssbb = new ShaderStringBuilder(); ah.customDeclaration(ssba); bh.customDeclaration(ssbb); if (ssba.ToCodeBlock() != ssbb.ToCodeBlock()) { equivalent = false; } } bHLSLProps.RemoveAt(i); } }); return(equivalent && (bHLSLProps.Count == 0)); }
void GenerateShaderPass(int targetIndex, PassDescriptor pass, ActiveFields activeFields) { // Early exit if pass is not used in preview if (m_Mode == GenerationMode.Preview && !pass.useInPreview) { return; } // -------------------------------------------------- // Debug // Get scripting symbols BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); bool isDebug = defines.Contains(kDebugSymbol); // -------------------------------------------------- // Setup // Initiailize Collectors var propertyCollector = new PropertyCollector(); var keywordCollector = new KeywordCollector(); m_OutputNode.owner.CollectShaderKeywords(keywordCollector, m_Mode); // Get upstream nodes from ShaderPass port mask List <AbstractMaterialNode> vertexNodes; List <AbstractMaterialNode> pixelNodes; GenerationUtils.GetUpstreamNodesForShaderPass(m_OutputNode, pass, out vertexNodes, out pixelNodes); // Track permutation indices for all nodes List <int>[] vertexNodePermutations = new List <int> [vertexNodes.Count]; List <int>[] pixelNodePermutations = new List <int> [pixelNodes.Count]; // Get active fields from upstream Node requirements ShaderGraphRequirementsPerKeyword graphRequirements; GenerationUtils.GetActiveFieldsAndPermutationsForNodes(m_OutputNode, pass, keywordCollector, vertexNodes, pixelNodes, vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements); // GET CUSTOM ACTIVE FIELDS HERE! // Get active fields from ShaderPass GenerationUtils.AddRequiredFields(pass.requiredFields, activeFields.baseInstance); // Get Port references from ShaderPass List <MaterialSlot> pixelSlots; List <MaterialSlot> vertexSlots; if (m_OutputNode is IMasterNode) { pixelSlots = GenerationUtils.FindMaterialSlotsOnNode(pass.pixelPorts, m_OutputNode); vertexSlots = GenerationUtils.FindMaterialSlotsOnNode(pass.vertexPorts, m_OutputNode); } else if (m_OutputNode is SubGraphOutputNode) { pixelSlots = new List <MaterialSlot>() { m_OutputNode.GetInputSlots <MaterialSlot>().FirstOrDefault(), }; vertexSlots = new List <MaterialSlot>(); } else { pixelSlots = new List <MaterialSlot>() { new Vector4MaterialSlot(0, "Out", "Out", SlotType.Output, Vector4.zero) { owner = m_OutputNode }, }; vertexSlots = new List <MaterialSlot>(); } // Function Registry var functionBuilder = new ShaderStringBuilder(); var functionRegistry = new FunctionRegistry(functionBuilder); // Hash table of named $splice(name) commands // Key: splice token // Value: string to splice Dictionary <string, string> spliceCommands = new Dictionary <string, string>(); // -------------------------------------------------- // Dependencies // Propagate active field requirements using dependencies // Must be executed before types are built foreach (var instance in activeFields.all.instances) { GenerationUtils.ApplyFieldDependencies(instance, pass.fieldDependencies); } // -------------------------------------------------- // Pass Setup // Name if (!string.IsNullOrEmpty(pass.displayName)) { spliceCommands.Add("PassName", $"Name \"{pass.displayName}\""); } else { spliceCommands.Add("PassName", "// Name: <None>"); } // Tags if (!string.IsNullOrEmpty(pass.lightMode)) { spliceCommands.Add("LightMode", $"\"LightMode\" = \"{pass.lightMode}\""); } else { spliceCommands.Add("LightMode", "// LightMode: <None>"); } // -------------------------------------------------- // Pass Code // Render State using (var renderStateBuilder = new ShaderStringBuilder()) { // Render states need to be separated by RenderState.Type // The first passing ConditionalRenderState of each type is inserted foreach (RenderStateType type in Enum.GetValues(typeof(RenderStateType))) { var renderStates = pass.renderStates?.Where(x => x.descriptor.type == type); if (renderStates != null) { foreach (RenderStateCollection.Item renderState in renderStates) { if (renderState.TestActive(activeFields)) { renderStateBuilder.AppendLine(renderState.value); break; } } } } string command = GenerationUtils.GetSpliceCommand(renderStateBuilder.ToCodeBlock(), "RenderState"); spliceCommands.Add("RenderState", command); } // Pragmas using (var passPragmaBuilder = new ShaderStringBuilder()) { if (pass.pragmas != null) { foreach (PragmaCollection.Item pragma in pass.pragmas) { if (pragma.TestActive(activeFields)) { passPragmaBuilder.AppendLine(pragma.value); } } } string command = GenerationUtils.GetSpliceCommand(passPragmaBuilder.ToCodeBlock(), "PassPragmas"); spliceCommands.Add("PassPragmas", command); } // Includes using (var preGraphIncludeBuilder = new ShaderStringBuilder()) { if (pass.includes != null) { foreach (IncludeCollection.Item include in pass.includes.Where(x => x.descriptor.location == IncludeLocation.Pregraph)) { if (include.TestActive(activeFields)) { preGraphIncludeBuilder.AppendLine(include.value); } } } string command = GenerationUtils.GetSpliceCommand(preGraphIncludeBuilder.ToCodeBlock(), "PreGraphIncludes"); spliceCommands.Add("PreGraphIncludes", command); } using (var postGraphIncludeBuilder = new ShaderStringBuilder()) { if (pass.includes != null) { foreach (IncludeCollection.Item include in pass.includes.Where(x => x.descriptor.location == IncludeLocation.Postgraph)) { if (include.TestActive(activeFields)) { postGraphIncludeBuilder.AppendLine(include.value); } } } string command = GenerationUtils.GetSpliceCommand(postGraphIncludeBuilder.ToCodeBlock(), "PostGraphIncludes"); spliceCommands.Add("PostGraphIncludes", command); } // Keywords using (var passKeywordBuilder = new ShaderStringBuilder()) { if (pass.keywords != null) { foreach (KeywordCollection.Item keyword in pass.keywords) { if (keyword.TestActive(activeFields)) { passKeywordBuilder.AppendLine(keyword.value); } } } string command = GenerationUtils.GetSpliceCommand(passKeywordBuilder.ToCodeBlock(), "PassKeywords"); spliceCommands.Add("PassKeywords", command); } // ----------------------------- // Generated structs and Packing code var interpolatorBuilder = new ShaderStringBuilder(); var passStructs = new List <StructDescriptor>(); if (pass.structs != null) { passStructs.AddRange(pass.structs.Select(x => x.descriptor)); foreach (StructCollection.Item shaderStruct in pass.structs) { if (shaderStruct.descriptor.packFields == false) { continue; //skip structs that do not need interpolator packs } List <int> packedCounts = new List <int>(); var packStruct = new StructDescriptor(); //generate packed functions if (activeFields.permutationCount > 0) { var generatedPackedTypes = new Dictionary <string, (ShaderStringBuilder, List <int>)>(); foreach (var instance in activeFields.allPermutations.instances) { var instanceGenerator = new ShaderStringBuilder(); GenerationUtils.GenerateInterpolatorFunctions(shaderStruct.descriptor, instance, out instanceGenerator); var key = instanceGenerator.ToCodeBlock(); if (generatedPackedTypes.TryGetValue(key, out var value)) { value.Item2.Add(instance.permutationIndex); } else { generatedPackedTypes.Add(key, (instanceGenerator, new List <int> { instance.permutationIndex }));
private void ProcessIncludeCommand(Token includeCommand, int lineEnd) { if (Expect(includeCommand.s, includeCommand.end, '(')) { Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd); if (!param.IsValid()) { Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1); } else { bool found = false; string includeLocation = null; // Use reverse order in the array, higher number element have higher priority in case $include exist in several directories for (int i = templatePaths.Length - 1; i >= 0; i--) { string templatePath = templatePaths[i]; includeLocation = Path.Combine(templatePath, param.GetString()); if (File.Exists(includeLocation)) { found = true; break; } } if (!found) { string errorStr = "ERROR: $include cannot find file : " + param.GetString() + ". Looked into:\n"; foreach (string templatePath in templatePaths) { errorStr += "// " + templatePath + "\n"; } Error(errorStr, includeCommand.s, param.start); } else { int endIndex = result.length; using (var temp = new ShaderStringBuilder()) { // Wrap in debug mode if (isDebug) { result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendNewLine(); } // Recursively process templates ProcessTemplateFile(includeLocation); // Wrap in debug mode if (isDebug) { result.AppendNewLine(); result.AppendLine("//-------------------------------------------------------------------------------------"); result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString()); result.AppendLine("//-------------------------------------------------------------------------------------"); } result.AppendNewLine(); // Required to enforce indentation rules // Append lines from this include into temporary StringBuilder // Reduce result length to remove this include temp.AppendLines(result.ToString(endIndex, result.length - endIndex)); result.length = endIndex; result.AppendLines(temp.ToCodeBlock()); } } } } }