/// <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); }
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 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> /// 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> /// 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> /// Get text from scene objects. /// </summary> /// <param name="scene"></param> /// <param name="cmd"></param> /// <returns></returns> private static string GetText(Dict scene, Compiler.Command cmd) { GLText text = null; string dir = Path.GetDirectoryName(cmd.File) + Path.DirectorySeparatorChar; if (scene.TryGetValue(cmd[0].Text, ref text)) { return(text.Text.Trim()); } else if (File.Exists(cmd[0].Text)) { return(File.ReadAllText(cmd[0].Text)); } else if (File.Exists(dir + cmd[0].Text)) { return(File.ReadAllText(dir + cmd[0].Text)); } return(null); }
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)); } }
/// <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); }
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)); }
public static CompileException Add(this CompileException err, string message, Compiler.Command cmd) { return(err.Add(message, cmd.File, cmd.LineInFile)); }
public static bool TryGetValue <T>(this Dict dict, string key, out T obj, Compiler.Command cmd, CompileException err) where T : GLObject { return(dict.TryGetValue(key, out obj, cmd.LineInFile, cmd.File, err)); }
/// <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, }); }
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); }