/// <summary> /// Processes an ifdef/else/endif block where Interpret denotes the success of the if statement. Returns true if exited on an endif or false /// if exited on an else. /// </summary> private static bool _ProcessBlock(IEnumerator<string> LineEnumerator, Path File, PrecompilerInput Input, StringBuilder Output, bool Interpret) { while (LineEnumerator.MoveNext()) { string line = LineEnumerator.Current; // Does this line contain a directive? if (line.Length > 0) { if (line[0] == '#') { string[] lineparts = line.Split(' '); if (lineparts[0] == "#ifdef") { if (Interpret) { bool contains = Input.Constants.ContainsKey(lineparts[1]); if (!_ProcessBlock(LineEnumerator, File, Input, Output, contains)) { _ProcessBlock(LineEnumerator, File, Input, Output, !contains); } } else { if (!_ProcessBlock(LineEnumerator, File, Input, Output, false)) { _ProcessBlock(LineEnumerator, File, Input, Output, false); } } continue; } if (lineparts[0] == "#include") { if (Interpret) { string filepath = lineparts[1].Substring(1, lineparts[1].Length - 2); BuildSource(File.Parent.Lookup(filepath), Input, Output); } continue; } if (lineparts[0] == "#else") { return false; } if (lineparts[0] == "#endif") { return true; } if (Interpret) { if (lineparts[0] == "#define") { if (lineparts.Length > 2) { Input.Define(lineparts[1], lineparts[2]); } else { Input.Define(lineparts[1]); } continue; } if (lineparts[0] == "#undef") { Input.Undefine(lineparts[1]); continue; } Output.AppendLine(line); } } else { if (Interpret) { // Replace constants Dictionary<int, KeyValuePair<int, string>> matches = new Dictionary<int, KeyValuePair<int, string>>(); foreach (KeyValuePair<string, string> constant in Input.Constants) { int ind = line.IndexOf(constant.Key); while (ind >= 0) { int size = constant.Key.Length; KeyValuePair<int, string> lastmatch; if (matches.TryGetValue(ind, out lastmatch)) { if (lastmatch.Key < size) { matches[ind] = new KeyValuePair<int, string>(size, constant.Value); } } else { matches[ind] = new KeyValuePair<int, string>(size, constant.Value); } ind = line.IndexOf(constant.Key, ind + 1); } } if (matches.Count > 0) { int c = 0; var orderedmatches = new List<KeyValuePair<int, KeyValuePair<int, string>>>(matches); orderedmatches.Sort(delegate(KeyValuePair<int, KeyValuePair<int, string>> a, KeyValuePair<int, KeyValuePair<int, string>> b) { if (a.Key > b.Key) return 1; if (a.Key < b.Key) return -1; return 0; }); foreach (KeyValuePair<int, KeyValuePair<int, string>> match in orderedmatches) { Output.Append(line.Substring(c, match.Key - c)); Output.Append(match.Value.Value); c = match.Key + match.Value.Key; } Output.AppendLine(line.Substring(c)); } else { Output.AppendLine(line); } } } } } return true; }
/// <summary> /// Precompiles the source code defined by the lines with the specified constants defined. Outputs the precompiled source /// to the given stringbuilder. /// </summary> public static void BuildSource(Path File, PrecompilerInput Input, StringBuilder Output) { string[] lines = Input.GetFile(File); _ProcessBlock(((IEnumerable<string>)lines).GetEnumerator(), File, Input, Output, true); }
/// <summary> /// Loads a shader from the specified file using the specified input. /// </summary> public static Shader Load(Path File, PrecompilerInput Input) { int vshade = GL.CreateShader(ShaderType.VertexShader); int fshade = GL.CreateShader(ShaderType.FragmentShader); StringBuilder vshadesource = new StringBuilder(); StringBuilder fshadesource = new StringBuilder(); PrecompilerInput vpce = Input.Copy(); PrecompilerInput fpce = Input.Copy(); vpce.Define("_VERTEX_", "1"); fpce.Define("_FRAGMENT_", "1"); BuildSource(File, vpce, vshadesource); GL.ShaderSource(vshade, vshadesource.ToString()); GL.CompileShader(vshade); string vinfo = GL.GetShaderInfoLog(vshade); BuildSource(File, fpce, fshadesource); GL.ShaderSource(fshade, fshadesource.ToString()); GL.CompileShader(fshade); string finfo = GL.GetShaderInfoLog(fshade); if (false) { if (finfo.Length > 0 || vinfo.Length > 0) { throw new Exception("Shader error"); } } Shader shade = new Shader(); shade.Program = GL.CreateProgram(); GL.AttachShader(shade.Program, vshade); GL.AttachShader(shade.Program, fshade); GL.LinkProgram(shade.Program); return shade; }