/// <summary> /// Create a new external class instance by processing the specified compiler block. /// </summary> /// <param name="block"></param> /// <param name="cmd"></param> /// <param name="err"></param> /// <returns></returns> private object CreateInstance(Compiler.Block block, Compiler.Command cmd, Dict scene, CompileException err) { // check if the command is valid if (cmd.ArgCount < 2) { err.Add("'class' command must specify a class name.", block); return(null); } // create OpenGL name lookup dictionary var glNames = new Dictionary <string, int>(scene.Count); scene.Keys.ForEach(scene.Values, (k, v) => glNames.Add(k, v.glname)); // create main class from compiled files var classname = cmd[1].Text; var instance = CompilerResults.CompiledAssembly.CreateInstance( classname, false, BindingFlags.Default, null, new object[] { block.Name, ToDict(block), glNames }, CultureInfo.CurrentCulture, null); if (instance == null) { throw err.Add($"Main class '{classname}' could not be found.", cmd); } InvokeMethod <List <string> >(instance, "GetErrors")?.ForEach(msg => err.Add(msg, cmd)); return(instance); }
/// <summary> /// Create a new external class instance by processing the specified compiler block. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="err"></param> /// <returns></returns> internal static object CreateInstance(Compiler.Block block, Dict scene, CompileException err) { // GET CLASS COMMAND var cmds = block["class"].ToList(); if (cmds.Count == 0) { err.Add("Instance must specify a 'class' command " + "(e.g., class csharp_name class_name).", block); return(null); } var cmd = cmds.First(); // check command if (cmd.ArgCount < 1) { err.Add("'class' command must specify a csharp object name.", cmd); return(null); } // FIND CSHARP CLASS DEFINITION var csharp = scene.GetValueOrDefault <GLCsharp>(cmd[0].Text); if (csharp == null) { err.Add($"Could not find csharp code '{cmd[0].Text}' of command '{cmd.Text}' ", cmd); return(null); } // INSTANTIATE CSHARP CLASS return(csharp.CreateInstance(block, cmd, scene, err)); }
/// <summary> /// Create OpenGL object. Standard object constructor for ProtoFX. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="debugging"></param> public GLCsharp(Compiler.Block block, Dict scene, bool debugging) : base(block.Name, block.Anno) { var err = new CompileException($"csharp '{Name}'"); // PARSE ARGUMENTS Cmds2Fields(block, err); // check for errors if (err.HasErrors) { throw err; } if (File == null || File.Length == 0) { return; } // LOAD ADDITIONAL ASSEMBLIES if (Assembly != null) { foreach (var assemblypath in Assembly) { try { System.Reflection.Assembly.LoadFrom(assemblypath); } catch (FileNotFoundException) { err.Add($"Assembly file '{assemblypath}' cound not be found.", block); } catch (FileLoadException) { err.Add($"Assembly '{assemblypath}' cound not be loaded.", block); } catch { err.Add($"Unknown exception when loading assembly '{assemblypath}'.", block); } } } // replace placeholders with actual path var dir = Path.GetDirectoryName(block.Filename) + Path.DirectorySeparatorChar; var filepath = ProcessPaths(dir, File); // COMPILE FILES CompilerResults = CompileFilesOrSource(filepath.ToArray(), Version, block, err); // check for errors if (err.HasErrors) { throw err; } }
/// <summary> /// Link image or buffer object to the texture. /// </summary> /// <param name="file"></param> /// <param name="line"></param> /// <param name="err"></param> private void Link(string file, int line, CompileException err) { // IN CASE THIS IS A TEXTURE OBJECT if (glImg != null) { glname = glImg.glname; // get internal format GL.GetTextureLevelParameter(glname, 0, GetTextureParameter.TextureInternalFormat, out int f); Format = (GpuFormat)f; } // IN CASE THIS IS A BUFFER OBJECT else if (glBuff != null) { if (Format == 0) { throw err.Add($"No texture buffer format defined for " + "buffer '{buff}' (e.g. format RGBA8).", file, line); } // CREATE OPENGL OBJECT glname = GL.GenTexture(); GL.BindTexture(TextureTarget.TextureBuffer, glname); GL.TexBuffer(TextureBufferTarget.TextureBuffer, (SizedInternalFormat)Format, glBuff.glname); GL.BindTexture(TextureTarget.TextureBuffer, 0); } }
private void ParseImgCmd(Compiler.Command cmd, Dict classes, CompileException err) { if (cmd.ArgCount != 1 && cmd.ArgCount != 6) { err.Add("Arguments of the 'img' command are invalid.", cmd); return; } // specify argument types var types = new[] { typeof(GLTexture), typeof(int), typeof(int), typeof(int), typeof(TextureAccess), typeof(GpuFormat), typeof(string) }; // specify mandatory arguments var mandatory = new[] { new[] { true, true, true, true, true, true, false }, new[] { false, true, false, false, false, false, false }, }; // parse command arguments (var values, var unused) = cmd.Parse(types, mandatory, classes, err); // if there are no errors, add the object to the pass if (!err.HasErrors) { texImages.Add(new ResTexImg(values)); } }
/// <summary> /// Get xml text from scene structure by processing the specified command. /// </summary> /// <param name="cmd"></param> /// <param name="scene"></param> /// <param name="err"></param> /// <returns></returns> private static byte[] LoadXml(Compiler.Command cmd, Dict scene, CompileException err) { // Get text from file or text object string str = GetText(scene, cmd); if (str == null) { err.Add("Could not process command. Second argument must " + "be a name to a text object or a filename.", cmd); return(null); } try { // Parse XML string var document = new XmlDocument(); document.LoadXml(str); // Load data from XML var filedata = new byte[cmd.ArgCount - 1][]; for (int i = 1; i < cmd.ArgCount; i++) { try { filedata[i - 1] = DataXml.Load(document, cmd[i].Text); } catch (XmlException ex) { err.Add(ex.Message, cmd); } } // Merge data if (!err.HasErrors) { return(filedata.Cat().ToArray()); } } catch (Exception ex) { err.Add(ex.GetBaseException().Message, cmd); } return(null); }
private void ParseComputeCall(Compiler.Command cmd, Dict classes, CompileException err) { // check for errors if (cmd.ArgCount < 2 || cmd.ArgCount > 3) { err.Add("Compute command does not provide enough arguments " + "(e.g., 'compute num_groups_X num_groups_y num_groups_z' or " + "'compute buffer_name indirect_pointer').", cmd); return; } try { var call = new CompCall(); // this is an indirect compute call if (cmd.ArgCount == 2) { // indirect compute call buffer call.numGroupsX = (uint)classes.GetValue <GLBuffer>(cmd[0].Text, "First argument of compute command must be a buffer name").glname; // indirect compute call buffer pointer call.numGroupsY = cmd[1].Text.To <uint>("Argument must be an unsigned integer, " + "specifying a pointer into the indirect compute call buffer."); } // this is a normal compute call else { // number of compute groups call.numGroupsX = cmd[0].Text.To <uint>("Argument must be an unsigned integer, " + "specifying the number of compute groups in X."); call.numGroupsY = cmd[1].Text.To <uint>("Argument must be an unsigned integer, " + "specifying the number of compute groups in Y."); call.numGroupsZ = cmd[2].Text.To <uint>("Argument must be an unsigned integer, " + "specifying the number of compute groups in Z."); } compcalls.Add(call); } catch (CompileException ex) { err.Add(ex.Message, cmd); } }
/// <summary> /// Create OpenGL object specifying the referenced scene objects directly. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="glbuff"></param> /// <param name="glimg"></param> public GLTexture(Compiler.Block block, Dict scene, GLBuffer glbuff, GLImage glimg) : base(block.Name, block.Anno) { var err = new CompileException($"texture '{Name}'"); // PARSE ARGUMENTS Cmds2Fields(block, err); // set name glBuff = glbuff; glImg = glimg; // GET REFERENCES if (Buff != null) { scene.TryGetValue(Buff, out glBuff, block, err); } if (Img != null) { scene.TryGetValue(Img, out glImg, block, err); } if (glBuff != null && glImg != null) { err.Add("Only an image or a buffer can be bound to a texture object.", block); } if (glBuff == null && glImg == null) { err.Add("Ether an image or a buffer has to be bound to a texture object.", block); } // IF THERE ARE ERRORS THROW AND EXCEPTION if (err.HasErrors) { throw err; } // INCASE THIS IS A TEXTURE OBJECT Link(block.Filename, block.LineInFile, err); if (HasErrorOrGlError(err, block)) { throw err; } }
/// <summary> /// Set a field of the specified class to the specified value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="clazz"></param> /// <param name="field"></param> /// <param name="fieldType"></param> /// <param name="cmd"></param> /// <param name="err"></param> static private void SetValue <T>(T clazz, object field, Type fieldType, Compiler.Command cmd, CompileException err = null) { // check for errors if (cmd.ArgCount == 0) { err?.Add($"Command '{cmd.Text}' has no arguments (must have at least one).", cmd); } if (!fieldType.IsArray && cmd.ArgCount > 1) { err?.Add($"Command '{cmd.Text}' has too many arguments (more than one).", cmd); } if (err != null && err.HasErrors) { return; } object val = null; if (fieldType.IsArray) { var elType = fieldType.GetElementType(); var array = Array.CreateInstance(elType, cmd.Length); for (int i = 0; i < cmd.Length; i++) { array.SetValue(Convert.ChangeType(cmd[i].Text, elType, CultureInfo.CurrentCulture), i); } val = array; } else { val = fieldType.IsEnum // if this is an enum, convert the string to an enum value ? Convert.ChangeType(Enum.Parse(fieldType, cmd[0].Text, true), fieldType) // else try to convert it to the field type : Convert.ChangeType(cmd[0].Text, fieldType, CultureInfo.CurrentCulture); } // set value of the field field.GetType() .GetMethod("SetValue", new[] { typeof(object), typeof(object) }) .Invoke(field, new object[] { clazz, val }); }
/// <summary> /// Check for compiler and OpenGL errors. /// </summary> /// <param name="err"></param> /// <param name="file"></param> /// <param name="line"></param> /// <returns></returns> static protected bool HasErrorOrGlError(CompileException err, string file, int line) { var errcode = GL.GetError(); if (errcode != ErrorCode.NoError) { err.Add($"OpenGL error '{errcode}' occurred.", file, line); return(true); } return(err.HasErrors); }
/// <summary> /// Check for compiler and OpenGL errors. /// </summary> /// <param name="err"></param> /// <param name="block"></param> /// <returns></returns> static protected bool HasErrorOrGlError(CompileException err, Compiler.Block block) { var errcode = GL.GetError(); if (errcode != ErrorCode.NoError) { err.Add($"OpenGL error '{errcode}' occurred.", block); return(true); } return(err.HasErrors); }
/// <summary> /// Create a new external method-call by processing the specified compiler command. /// </summary> /// <param name="cmd"></param> /// <param name="err"></param> /// <returns></returns> private MethodInfo GetMethod(Compiler.Command cmd, CompileException err) { // check if the command is valid if (cmd.ArgCount < 2) { err.Add("'class' command must specify a class name.", cmd); return(null); } if (cmd.ArgCount < 3) { err.Add("'class' command must specify a method name.", cmd); return(null); } var classname = cmd[1].Text; var methodname = cmd[2].Text; var type = CompilerResults.CompiledAssembly.GetType(classname); return(type?.GetMethod(methodname, BindingFlags.Public | BindingFlags.Static)); }
/// <summary> /// Create a new external method-call by processing the specified compiler command. /// </summary> /// <param name="cmd"></param> /// <param name="err"></param> /// <returns></returns> internal static MethodInfo GetMethod(Compiler.Command cmd, Dict scene, CompileException err) { // check command if (cmd.ArgCount < 1) { err.Add("'class' command must specify a csharp object name.", cmd); return(null); } // FIND CSHARP CLASS DEFINITION var csharp = scene.GetValueOrDefault <GLCsharp>(cmd[0].Text); if (csharp == null) { err.Add($"Could not find csharp code '{cmd[0].Text}' of command '{cmd.Text}' ", cmd); return(null); } // INSTANTIATE CSHARP CLASS return(csharp.GetMethod(cmd, err)); }
/// <summary> /// Parse command line and attach the buffer object /// to the specified unit (output stream). /// </summary> /// <param name="unit">Vertex output stream unit.</param> /// <param name="cmd">Command line to process.</param> /// <param name="scene">Dictionary of scene objects.</param> /// <param name="err">Compiler exception collector.</param> private void Attach(int unit, Compiler.Command cmd, Dict scene, CompileException err) { if (cmd.ArgCount == 0) { err.Add("Command buff needs at least one attribute (e.g. 'buff buff_name')", cmd); return; } // get buffer var buf = scene.GetValueOrDefault <GLBuffer>(cmd[0].Text); if (buf == null) { err.Add($"The name '{cmd[0]}' does not reference an object of type 'buffer'.", cmd); return; } // parse offset int offset = 0; if (cmd.ArgCount > 1 && int.TryParse(cmd[1].Text, out offset) == false) { err.Add($"The second parameter (offset) of buff {unit} is invalid.", cmd); return; } // parse size int size = buf.Size; if (cmd.ArgCount > 2 && int.TryParse(cmd[2].Text, out size) == false) { err.Add($"The third parameter (size) of buff {unit} is invalid.", cmd); return; } // bind buffer to transform feedback GL.BindBufferRange(BufferRangeTarget.TransformFeedbackBuffer, unit, buf.glname, (IntPtr)offset, (IntPtr)size); }
/// <summary> /// Parse the command and extract arguments as values. /// </summary> /// <param name="types">List of argument types.</param> /// <param name="mandatory">Specifies which of this arguments are mandatory.</param> /// <param name="unusedArgs">List of arguments the where not parsed.</param> /// <param name="scene">Dictionary of scene objects.</param> /// <param name="err"></param> /// <returns>List of objects values. If a value could not be /// parsed, the returned value will be null.</returns> public (object[], string[]) Parse(Type[] types, bool[][] mandatory, Dict scene, CompileException err = null) { var values = new object[types.Length]; // parse command arguments var lastArgUsed = 0; for (var a = 0; a < Length; a++) { var arg = this[a]; var I = values .Zip(Enumerable.Range(0, types.Length), (x, i) => x == null ? i : -1) .Where(x => x >= 0); foreach (var i in I) { try { values[i] = types[i].IsSubclassOf(typeof(GLObject)) ? scene.GetValueOrDefault <GLObject>(arg.Text) : types[i].IsEnum ? Enum.Parse(types[i], arg.Text, true) : Convert.ChangeType(arg.Text, types[i], CultureInfo.CurrentCulture); if (values[i] != null) { lastArgUsed = a; break; } } catch { } } } // return list of unused arguments var unusedArgs = this.Skip(lastArgUsed + 1).Select(x => x.Text).ToArray(); // check for errors var valid = values.Select(x => x != null); for (int i = 0; i < mandatory.Length; i++) { if (mandatory[i].Zip(valid, (m, v) => !m | v).All(x => x)) { return(values, unusedArgs); } } err?.Add("Command has one or more invalid arguments.", this); return(values, unusedArgs); }
/// <summary> /// Get text from scene structure by processing the specified command. /// </summary> /// <param name="cmd"></param> /// <param name="scene"></param> /// <param name="err"></param> /// <returns></returns> private static byte[] LoadText(Compiler.Command cmd, Dict scene, CompileException err) { // Get text from file or text object var str = GetText(scene, cmd); if (str == null) { err.Add("Could not process command. Second argument must " + "be a name to a text object or a filename.", cmd); return(null); } // Convert text to byte array return(str.ToCharArray().ToBytes()); }
private void ParseCsharpExec(Compiler.Command cmd, Dict classes, CompileException err) { // check if command provides the correct amount of parameters if (cmd.ArgCount == 0) { err.Add("Not enough arguments for exec command.", cmd); return; } // get instance if (!classes.TryGetValue(cmd[0].Text, out GLInstance instance, cmd, err)) { return; } csexec.Add(instance); }
/// <summary> /// Try to find the value to a key. If the key could not be found add an exception message. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key">Key to search for.</param> /// <param name="obj">Output object reference.</param> /// <param name="file">Specify the file identifying an exception if it occurs.</param> /// <param name="line">Specify the file line identifying an exception if it occurs.</param> /// <param name="err">Add new exceptions to this existing one.</param> /// <returns></returns> public bool TryGetValue <T>(string key, out T obj, int line, string file, CompileException err) where T : GLObject { // try to find the object instance if ((obj = GetValueOrDefault <T>(key)) != default(T)) { return(true); } // get class name of object type var classname = typeof(T).Name.Substring(2).ToLower(); err.Add($"The name '{key}' could not be found or does not " + $"reference an object of type '{classname}'.", file, line); return(false); }
private void ParseSampCmd(Compiler.Command cmd, Dict classes, CompileException err) { if (cmd.ArgCount != 1 && cmd.ArgCount != 2) { err.Add("Arguments of the 'samp' command are invalid.", cmd); return; } // specify argument types var types = new[] { typeof(GLSampler), typeof(int), typeof(string) }; // specify mandatory arguments var mandatory = new[] { new[] { true, true, false }, new[] { false, true, false } }; // parse command arguments (var values, var unused) = cmd.Parse(types, mandatory, classes, err); // if there are no errors, add the object to the pass if (!err.HasErrors) { sampler.Add(new Res <GLSampler>(values)); } }
private void ParseOpenGLCall(Compiler.Command cmd, CompileException err) { // find OpenGL method var mname = cmd.Name.StartsWith("gl") ? cmd.Name.Substring(2) : cmd.Name; var mtype = FindMethod(mname, cmd.ArgCount); if (mtype == null) { if (GetFxField(mname) == null) { err.Add("Unknown command '" + cmd.Text + "'", cmd); } return; } // get method parameter types var param = mtype.GetParameters(); var inval = new object[param.Length]; // convert strings to parameter types for (int i = 0; i < param.Length; i++) { if (param[i].ParameterType.IsEnum) { inval[i] = Convert.ChangeType( Enum.Parse(param[i].ParameterType, cmd[i].Text, true), param[i].ParameterType); } else { inval[i] = Convert.ChangeType(cmd[i].Text, param[i].ParameterType, CultureInfo.CurrentCulture); } } glfunc.Add(new GLMethod(mtype, inval)); }
/// <summary> /// Create OpenGL object. Standard object constructor for ProtoFX. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="debugging"></param> public GLShader(Compiler.Block block, Dict scene, bool debugging) : base(block.Name, block.Anno) { var err = new CompileException($"shader '{Name}'"); // COMPILE AND LINK SHADER INTO A SHADER PROGRAM switch (Anno) { case "vert": ShaderType = ShaderType.VertexShader; break; case "tess": ShaderType = ShaderType.TessControlShader; break; case "eval": ShaderType = ShaderType.TessEvaluationShader; break; case "geom": ShaderType = ShaderType.GeometryShader; break; case "frag": ShaderType = ShaderType.FragmentShader; break; case "comp": ShaderType = ShaderType.ComputeShader; break; default: throw err.Add($"Shader type '{Anno}' is not supported.", block); } glname = GL.CreateShaderProgram(ShaderType, 1, new[] { block.Body }); // check for errors GL.GetProgram(glname, GetProgramParameterName.LinkStatus, out int status); if (status != 1) { err.Add($"\n{GL.GetProgramInfoLog(glname)}", block); } if (HasErrorOrGlError(err, block)) { throw err; } // CREATE CSHARP DEBUG CODE string code; CompilerResults rs; if (debugging) { code = Converter.Shader2Class(ShaderType, Name, block.Body, block.BodyIndex); rs = GLCsharp.CompileFilesOrSource(new[] { code }, null, block, err, new[] { Name }); if (rs.Errors.Count == 0) { DebugShader = (Shader)rs.CompiledAssembly.CreateInstance( $"App.Glsl.{Name}", false, BindingFlags.Default, null, new object[] { block.LineInFile }, CultureInfo.CurrentCulture, null); } } // check for errors if (err.HasErrors) { throw err; } }
public static CompileException Add(this CompileException err, string message, Compiler.Command cmd) { return(err.Add(message, cmd.File, cmd.LineInFile)); }
public static CompileException Add(this CompileException err, string message, Compiler.Block block) { return(err.Add(message, block.Filename, block.LineInFile)); }
/// <summary> /// Create OpenGL object. Standard object constructor for ProtoFX. /// </summary> /// <param name="block"></param> /// <param name="scene"></param> /// <param name="genDebugInfo"></param> public GLPass(Compiler.Block block, Dict scene, bool genDebugInfo) : base(block.Name, block.Anno, 309, genDebugInfo) { var err = new CompileException($"pass '{Name}'"); GenDebugInfo = genDebugInfo; /// PARSE COMMANDS AND CONVERT THEM TO CLASS FIELDS Cmds2Fields(block, err); /// PARSE COMMANDS foreach (var cmd in block) { // ignore class fields var field = GetType().GetField(cmd.Name, Instance | Public | NonPublic); var attr = field?.GetCustomAttributes(typeof(FxField), false); if (attr?.Length > 0) { continue; } using (var e = err | $"command '{cmd.Name}' line {cmd.LineInFile}") { switch (cmd.Name) { case "draw": ParseDrawCall(cmd, scene, e); break; case "compute": ParseComputeCall(cmd, scene, e); break; case "tex": ParseTexCmd(cmd, scene, e); break; case "img": ParseImgCmd(cmd, scene, e); break; case "samp": ParseSampCmd(cmd, scene, e); break; case "exec": ParseCsharpExec(cmd, scene, e); break; case "vertout": vertoutput = new Vertoutput(cmd, scene, e); break; case "fragout": scene.TryGetValue(cmd[0].Text, out fragoutput, cmd, e); break; default: ParseOpenGLCall(cmd, e); break; } } } if (err.HasErrors) { throw err; } /// CREATE OPENGL OBJECT if (Vert != null || Comp != null) { GL.CreateProgramPipelines(1, out glname); // Attach shader objects. // First try attaching a compute shader. If that // fails, try attaching the default shader pipeline. if ((glcomp = Attach(block, Comp, scene, err)) == null) { glvert = Attach(block, Vert, scene, err); gltess = Attach(block, Tess, scene, err); gleval = Attach(block, Eval, scene, err); glgeom = Attach(block, Geom, scene, err); glfrag = Attach(block, Frag, scene, err); } // get debug shaders if (GenDebugInfo) { if (glcomp != null) { dbgcomp = (CompShader)glcomp.DebugShader; } else { Shader prev = dbgvert = (VertShader)glvert.DebugShader; dbgtess = (TessShader)gltess?.DebugShader; dbgeval = (EvalShader)gleval?.DebugShader; dbggeom = (GeomShader)glgeom?.DebugShader; dbgfrag = (FragShader)glfrag?.DebugShader; if (dbgtess != null) { dbgtess.Prev = prev; prev = dbgtess; } if (dbgeval != null) { dbgeval.Prev = prev; prev = dbgeval; } if (dbggeom != null) { dbggeom.Prev = prev; prev = dbggeom; } } } } /// CHECK FOR ERRORS if (GL.GetError() != ErrorCode.NoError) { err.Add($"OpenGL error '{GL.GetError()}' occurred " + "during shader program creation.", block); } if (err.HasErrors) { throw err; } }
/// <summary> /// Compile a list of files or a list of source code. /// </summary> /// <param name="code"></param> /// <param name="block"></param> /// <param name="err"></param> /// <returns></returns> internal static CompilerResults CompileFilesOrSource(string[] code, string version, Compiler.Block block, CompileException err, string[] tmpNames = null) { CompilerResults rs = null; try { var compilerParams = new CompilerParameters(); // set compicompiler parameters compilerParams.GenerateInMemory = true; compilerParams.GenerateExecutable = false; compilerParams.TempFiles = new TempFileCollection("tmp", false); #if DEBUG compilerParams.IncludeDebugInformation = true; compilerParams.CompilerOptions = "/define:DEBUG"; #else compilerParams.IncludeDebugInformation = false; #endif // add assemblies compilerParams.ReferencedAssemblies.Add( System.Reflection.Assembly.GetExecutingAssembly().Location); compilerParams.ReferencedAssemblies.AddRange( Properties.Resources.CSHARP_REFERENCES.Split('\n') .Select(s => s.Trim()).ToArray()); // select compiler version var provider = version != null ? new CSharpCodeProvider(new Dictionary <string, string> { { "CompilerVersion", version } }) : new CSharpCodeProvider(); var check = code.Count(x => IsFilename(x)); if (check == code.Length) { rs = provider.CompileAssemblyFromFile(compilerParams, code); } else if (check == 0) { #if DEBUG Directory.CreateDirectory("tmp"); var filenames = new string[code.Length]; for (int i = 0; i < filenames.Length; i++) { filenames[i] = $"tmp{Path.DirectorySeparatorChar}tmp_{tmpNames[i]}.cs"; if (System.IO.File.Exists(filenames[i])) { var tmp = System.IO.File.ReadAllText(filenames[i]); if (tmp != code[i]) { System.IO.File.WriteAllText(filenames[i], code[i]); } } else { System.IO.File.WriteAllText(filenames[i], code[i]); } } rs = provider.CompileAssemblyFromFile(compilerParams, filenames); #else rs = provider.CompileAssemblyFromSource(compilerParams, code); #endif } else { throw err.Add("Cannot mix filenames and source code" + "strings when compiling C# code.", block); } } catch (DirectoryNotFoundException ex) { throw err.Add(ex.Message, block); } catch (FileNotFoundException ex) { throw err.Add(ex.Message, block); } finally { // check for compiler errors if (rs?.Errors.Count != 0) { string msg = ""; foreach (var message in rs.Errors) { msg += $"\n{message}"; } err.Add(msg, block); } } return(rs); }
private void ParseDrawCall(Compiler.Command cmd, Dict classes, CompileException err) { var args = new List <int>(); GLVertinput vertexin = null; GLVertoutput vertout = null; GLBuffer indexbuf = null; GLBuffer indirect = null; bool modeIsSet = false; bool typeIsSet = false; PrimType primitive = 0; ElementType indextype = 0; // parse draw call arguments foreach (var arg in cmd) { if (classes.TryGetValue(arg.Text, ref vertexin)) { continue; } if (classes.TryGetValue(arg.Text, ref vertout)) { continue; } if (classes.TryGetValue(arg.Text, ref indexbuf)) { continue; } if (classes.TryGetValue(arg.Text, ref indirect)) { continue; } if (int.TryParse(arg.Text, out int val)) { args.Add(val); } else if (typeIsSet == false && Enum.TryParse(arg.Text, true, out indextype)) { typeIsSet = true; } else if (modeIsSet == false && Enum.TryParse(arg.Text, true, out primitive)) { modeIsSet = true; } else { err.Add($"Unable to process argument '{arg.Text}'.", cmd); } } if (err.HasErrors) { return; } // a draw call must specify a primitive type if (modeIsSet == false) { err.Add("Draw call must specify a primitive type (e.g. triangles, " + "trianglefan, lines, points, ...).", cmd); return; } // determine the right draw call function int bits = (vertout != null ? 1 : 0) | (indexbuf != null ? 2 : 0) | (indirect != null ? 4 : 0) | (typeIsSet ? 8 : 0); if (!Enum.IsDefined(typeof(DrawFunc), bits)) { err.Add("Draw call function not recognized or ambiguous.", cmd); return; } var drawfunc = (DrawFunc)bits; // get index buffer object (if present) and find existing MultiDraw class var multidrawcall = drawcalls.Find( x => x.vertexin == (vertexin != null ? vertexin.glname : 0) && x.indexbuf == (indexbuf != null ? indexbuf.glname : 0) && x.vertout == (vertout != null ? vertout.glname : 0) && x.indirect == (indirect != null ? indirect.glname : 0)) ?? new MultiDrawCall(drawfunc, vertexin, vertout, indexbuf, indirect); // add new draw command to the MultiDraw class multidrawcall.cmd.Add(new DrawCall(drawfunc, primitive, indextype, args)); drawcalls.Add(multidrawcall); }
/// <summary> /// Parse command line and attach the buffer object /// to the specified unit (input stream). /// </summary> /// <param name="unit"></param> /// <param name="cmd"></param> /// <param name="scene"></param> /// <param name="err"></param> private void Attach(int unit, Compiler.Command cmd, Dict scene, CompileException err) { // check commands for errors if (cmd.ArgCount < 3) { err.Add("Command attr needs at least 3 attributes (e.g. 'attr buff_name float 4')", cmd); return; } // parse command arguments string buffname = cmd[0].Text; string typename = cmd[1].Text; int length = int.Parse(cmd[2].Text); int stride = cmd.ArgCount > 3 ? int.Parse(cmd[3].Text) : 0; int offset = cmd.ArgCount > 4 ? int.Parse(cmd[4].Text) : 0; int divisor = cmd.ArgCount > 5 ? int.Parse(cmd[5].Text) : 0; if (scene.TryGetValue(buffname, out GLBuffer buff, cmd, err) == false) { err.Add($"Buffer '{buffname}' could not be found.", cmd); return; } // enable vertex array attribute GL.BindBuffer(BufferTarget.ArrayBuffer, buff.glname); GL.EnableVertexAttribArray(unit); // bind buffer to vertex array attribute int type = 0; if (Enum.TryParse(typename, true, out VertAttrIntType typei)) { GL.VertexAttribIPointer(unit, length, (IntType)(type = (int)typei), stride, (IntPtr)offset); } else if (Enum.TryParse(typename, true, out VertAttrType typef)) { GL.VertexAttribPointer(unit, length, (PointerType)(type = (int)typef), false, stride, offset); } else { err.Add($"Type '{typename}' is not supported.", cmd); } if (divisor > 0) { GL.VertexAttribDivisor(unit, divisor); } GL.BindBuffer(BufferTarget.ArrayBuffer, 0); // add vertex attribute attributes.Add(new VertAttr() { buffer = buff, type = type, length = length, stride = stride, offset = offset, divisor = divisor, }); }