/// <summary> /// Process shader source lines to resolve #include directives. /// </summary> /// <param name="includeLibrary"> /// A <see cref="ShaderIncludeLibrary"/> determining the shader include file system. /// </param> /// <param name="cctx"> /// A <see cref="ShaderCompilerContext"/> that specify the compiler parameteres. /// </param> /// <param name="shaderSource"> /// A <see cref="IEnumerable{String}"/> that specify the shader source lines. Null items in the enumeration /// will be ignored. /// </param> /// <returns> /// It returns the processed source lines <paramref name="shaderSource"/>, but without any #include directive. Each #include /// directive will be replaced by the corresponding text depending on <paramref name="cctx"/>. /// </returns> /// <remarks> /// <para> /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// Exception throw if <paramref name="includeLibrary"/>, <paramref name="cctx"/> or <paramref name="shaderSource"/> is null. /// </exception> public static List<string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, List<string> shaderSource) { if (includeLibrary == null) throw new ArgumentNullException("includeLibrary"); if (cctx == null) throw new ArgumentNullException("cctx"); if (shaderSource == null) throw new ArgumentNullException("sSource"); IncludeProcessorContext ictx = new IncludeProcessorContext(); return (Process(includeLibrary, cctx, ictx, shaderSource)); }
/// <summary> /// Process shader source lines to resolve #include directives. /// </summary> /// <param name="includeLibrary"> /// A <see cref="ShaderIncludeLibrary"/> determining the shader include file system. /// </param> /// <param name="cctx"> /// A <see cref="ShaderCompilerContext"/> that specify the compiler parameteres. /// </param> /// <param name="shaderSource"> /// A <see cref="IEnumerable{String}"/> that specify the shader source lines. Null items in the enumeration /// will be ignored. /// </param> /// <returns> /// It returns the processed source lines <paramref name="shaderSource"/>, but without any #include directive. Each #include /// directive will be replaced by the corresponding text depending on <paramref name="cctx"/>. /// </returns> /// <remarks> /// <para> /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// Exception throw if <paramref name="includeLibrary"/>, <paramref name="cctx"/> or <paramref name="shaderSource"/> is null. /// </exception> public static List <string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, List <string> shaderSource) { if (includeLibrary == null) { throw new ArgumentNullException("includeLibrary"); } if (cctx == null) { throw new ArgumentNullException("cctx"); } if (shaderSource == null) { throw new ArgumentNullException("sSource"); } IncludeProcessorContext ictx = new IncludeProcessorContext(); return(Process(includeLibrary, cctx, ictx, shaderSource)); }
/// <summary> /// Process shader source lines to resolve #include directives. /// </summary> /// <param name="shaderSource"> /// A <see cref="IEnumerable{String}"/> that specify the shader source lines. Null items in the enumeration /// will be ignored. /// </param> /// <param name="cctx"> /// A <see cref="ShaderCompilerContext"/> that specify the compiler parameteres. /// </param> /// <param name="includeLibrary"> /// A <see cref="ShaderIncludeLibrary"/> determining the shader include file system. /// </param> /// <returns> /// It returns the processed source lines <paramref name="shaderSource"/>, but without any #include directive. Each #include /// directive will be replaced by the corresponding text depending on <paramref name="cctx"/>. /// </returns> /// <remarks> /// <para> /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// Exception throw if <paramref name="includeLibrary"/>, <paramref name="cctx"/> or <paramref name="shaderSource"/> is null. /// </exception> private static List <string> ProcessIncludes(List <string> shaderSource, ShaderCompilerContext cctx, ShaderIncludeLibrary includeLibrary) { if (includeLibrary == null) { throw new ArgumentNullException("includeLibrary"); } if (cctx == null) { throw new ArgumentNullException("cctx"); } if (shaderSource == null) { throw new ArgumentNullException("sSource"); } IncludeProcessorContext ictx = new IncludeProcessorContext(); return(ProcessIncludes(shaderSource, cctx, includeLibrary, ictx)); }
private static List <string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, IncludeProcessorContext ictx, IEnumerable <string> shaderSource) { if (includeLibrary == null) { throw new ArgumentNullException("includeLibrary"); } if (cctx == null) { throw new ArgumentNullException("cctx"); } if (shaderSource == null) { throw new ArgumentNullException("sSource"); } List <string> processedSource = new List <string>(); // Shader includes not supported. Process them manually before submitting shader source text lines. foreach (string line in shaderSource) { // Ignore null items if (line == null) { continue; } if ((_RegexInclude.Match(line)).Success) { ShaderInclude shaderInclude = null; string includePath = ExtractIncludePath(line); string canonicalPath = String.Empty; if (includePath.StartsWith("/") == false) { // If <path> does not start with a forward slash, it is a path relative // to one of the ordered list of initial search points. if ((ictx.CurrentPath != String.Empty) && (_RegexIncludeAngular.Match(line).Success == false)) { // If it is quoted with double quotes in a previously included string, then the first // search point will be the tree location where the previously included // string had been found. If not found there, the search continues at // the beginning of the list of search points, as just described (see comment later). canonicalPath = NormalizeIncludePath(Path.Combine(ictx.CurrentPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) { shaderInclude = includeLibrary.GetInclude(canonicalPath); } } // If this path is quoted with angled brackets, the tree is searched relative to the // first search point in the ordered list, and then relative to each // subsequent search point, in order, until a matching path is found in // the tree. This is also the behavior if it is quoted with double // quotes in an initial (non-included) shader string. if (shaderInclude == null) { foreach (string includeSearchPath in cctx.Includes) { canonicalPath = NormalizeIncludePath(Path.Combine(includeSearchPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) { shaderInclude = includeLibrary.GetInclude(canonicalPath); break; } } } } else { // If <path> starts with a forward slash, whether it is quoted with // double quotes or with angled brackets, the list of search points is // ignored and <path> is looked up in the tree as described in Appendix // A. canonicalPath = includePath; if (includeLibrary.IsPathDefined(canonicalPath) == false) { throw new InvalidOperationException(String.Format("absolute include path \"{0}\" not existing", canonicalPath)); } shaderInclude = includeLibrary.GetInclude(canonicalPath); } if (shaderInclude == null) { throw new InvalidOperationException(String.Format("include path '{0}' not found", includePath)); } // Recurse on included source (it may contain other includes) IncludeProcessorContext ictxRecurse = new IncludeProcessorContext(); System.Diagnostics.Debug.Assert(String.IsNullOrEmpty(canonicalPath) == false); ictxRecurse.CurrentPath = canonicalPath; processedSource.AddRange(Process(includeLibrary, cctx, ictxRecurse, shaderInclude.Source)); } else { processedSource.Add(line); } } return(processedSource); }
public async Task Process(IncludeProcessorContext context) { var reader = context.Reader; var writer = context.Writer; try { while (true) { var readResult = await reader.ReadAsync(); if (readResult.IsCanceled) { break; } var buffer = readResult.Buffer; if (readResult.IsCompleted && buffer.IsEmpty) { break; } if (TryReadInclude(readResult, out var start, out var end, out var include)) { var beforePosition = buffer.Slice(0, start); if (beforePosition.Length > 0) { //todo: fix var memory = writer.GetMemory((int)beforePosition.Length); beforePosition.CopyTo(memory.Span); writer.Advance((int)beforePosition.Length); await writer.FlushAsync(); } //todo: lookup the included file and copy to writer await WriteInclude(writer, include); await writer.FlushAsync(); // advance reader reader.AdvanceTo(end, end); } else { if (buffer.IsSingleSegment) { await writer.WriteAsync(buffer.First); } else { foreach (var memory in buffer) { await writer.WriteAsync(memory); } } await writer.FlushAsync(); reader.AdvanceTo(buffer.End); } }
private static List<string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, IncludeProcessorContext ictx, IEnumerable<string> shaderSource) { if (includeLibrary == null) throw new ArgumentNullException("includeLibrary"); if (cctx == null) throw new ArgumentNullException("cctx"); if (shaderSource == null) throw new ArgumentNullException("sSource"); List<string> processedSource = new List<string>(); // Shader includes not supported. Process them manually before submitting shader source text lines. foreach (string line in shaderSource) { // Ignore null items if (line == null) continue; if ((_RegexInclude.Match(line)).Success) { ShaderInclude shaderInclude = null; string includePath = ExtractIncludePath(line); string canonicalPath = String.Empty; if (includePath.StartsWith("/") == false) { // If <path> does not start with a forward slash, it is a path relative // to one of the ordered list of initial search points. if ((ictx.CurrentPath != String.Empty) && (_RegexIncludeAngular.Match(line).Success == false)) { // If it is quoted with double quotes in a previously included string, then the first // search point will be the tree location where the previously included // string had been found. If not found there, the search continues at // the beginning of the list of search points, as just described (see comment later). canonicalPath = NormalizeIncludePath(Path.Combine(ictx.CurrentPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) shaderInclude = includeLibrary.GetInclude(canonicalPath); } // If this path is quoted with angled brackets, the tree is searched relative to the // first search point in the ordered list, and then relative to each // subsequent search point, in order, until a matching path is found in // the tree. This is also the behavior if it is quoted with double // quotes in an initial (non-included) shader string. if (shaderInclude == null) { foreach (string includeSearchPath in cctx.Includes) { canonicalPath = NormalizeIncludePath(Path.Combine(includeSearchPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) { shaderInclude = includeLibrary.GetInclude(canonicalPath); break; } } } } else { // If <path> starts with a forward slash, whether it is quoted with // double quotes or with angled brackets, the list of search points is // ignored and <path> is looked up in the tree as described in Appendix // A. canonicalPath = includePath; if (includeLibrary.IsPathDefined(canonicalPath) == false) throw new InvalidOperationException(String.Format("absolute include path \"{0}\" not existing", canonicalPath)); shaderInclude = includeLibrary.GetInclude(canonicalPath); } if (shaderInclude == null) throw new InvalidOperationException(String.Format("include path '{0}' not found", includePath)); // Recurse on included source (it may contain other includes) IncludeProcessorContext ictxRecurse = new IncludeProcessorContext(); System.Diagnostics.Debug.Assert(String.IsNullOrEmpty(canonicalPath) == false); ictxRecurse.CurrentPath = canonicalPath; processedSource.AddRange(Process(includeLibrary, cctx, ictxRecurse, shaderInclude.Source)); } else processedSource.Add(line); } return (processedSource); }