public void AddShader(ShaderDefinition shader) { if (!_shaders.Contains(shader)) { _shaders.Add(shader); } }
private static List <ShaderProgram> TryPreprocess(string sourceCode) { // split into lines. var lines = sourceCode.Split(Environment.NewLine); // Find all Thundershock preprocessor macros. var macros = new List <PreprocessorMacro>(); var i = 0; foreach (var line in lines) { var lookFor = "#pragma ts "; var pragmaTs = line.IndexOf(lookFor, StringComparison.Ordinal); if (pragmaTs >= 0) { var content = line.Substring(pragmaTs + lookFor.Length); var data = new PreprocessorMacro { Line = i, Index = pragmaTs, Length = lookFor.Length + content.Length, Content = content }; macros.Add(data); } i++; } // Now we can go through the macros. var inProgram = false; var inShader = false; var program = null as ShaderProgram; var shader = null as ShaderDefinition; var shaderStart = -1; var programs = new List <ShaderProgram>(); foreach (var macro in macros) { if (string.IsNullOrWhiteSpace(macro.Content)) { Logger.GetLogger() .Log( $"Shader preprocessor: Warning PP1 (ln {macro.Line} ch {macro.Index}): Empty macro. Ignoring.", LogLevel.Warning); continue; } // Tokenize the preprocessor command. var command = macro.Content.Split(' ', StringSplitOptions.RemoveEmptyEntries); var name = command.First(); var args = command.Skip(1).ToArray(); if (name == "program") { if (inProgram) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Cannot define a new program inside the scope of another program. Did you forget a #pragma ts end?"); } if (!args.Any()) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Missing program name!"); } program = new ShaderProgram(args.First()); inProgram = true; continue; } if (name == "shader") { if (inShader) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Cannot define a shader inside the scope of another shader. Did you forget a #pragma ts end?"); } if (!inProgram) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Shaders must be defined inside the scope of a Program."); } if (!args.Any()) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Missing shader name!"); } shader = new ShaderDefinition(args.First()); shaderStart = macro.Line + 1; inShader = true; continue; } if (name == "compile") { if (inShader) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Cannot define a shader compilation inside the scope of a shader. Did you forget a #pragma ts end?"); } if (!inProgram) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Cannot define a shader compilation outside the scope of a Program."); } if (args.Length < 2) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Missing como;e type and shader name!"); } var sType = args[0]; var sName = args[1]; var type = sType switch { "vert" => ShaderCompilation.VertexShader, "frag" => ShaderCompilation.FragmentShader, _ => throw new ShaderPreprocessorException(macro.Line, macro.Index, "Unsupported shader type " + sType + ".") }; if (!program.HasShader(sName)) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Shader " + sName + " not defined in the program!"); } if (program.WillCompile(sName)) { throw new ShaderPreprocessorException(macro.Line, macro.Index, "Shader compilation has already been defined."); } program.SetCompileType(sName, type); continue; } if (name == "end") { if (inShader) { var srcBuilder = new StringBuilder(); for (var l = shaderStart; l < macro.Line; l++) { var sLine = lines[l]; if (l == macro.Line) { sLine = sLine.Substring(0, macro.Index); } srcBuilder.AppendLine(sLine); } shader.SourceCode = srcBuilder.ToString(); program.AddShader(shader); shader = null; shaderStart = -1; inShader = false; continue; } if (inProgram) { if (!program.HasCompilations) { Logger.GetLogger().Log("Empty shader program detected!", LogLevel.Warning); continue; } programs.Add(program); inProgram = false; program = null; continue; } } } return(programs); }