/// <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> /// 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> /// 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> /// Create class instance of a C# class compiled through GLCSharp. /// </summary> /// <param name="params">Input parameters for GLObject creation.</param> public GLInstance(Compiler.Block block, Dict scene, bool debugging) : base(block.Name, block.Anno) { var err = new CompileException($"instance '{Name}'"); // INSTANTIATE CSHARP CLASS FROM CODE BLOCK Instance = GLCsharp.CreateInstance(block, scene, err); if (err.HasErrors) { throw err; } // get Bind method from main class instance update = Instance.GetType().GetMethod("Update", new[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); // get Unbind method from main class instance endpass = Instance.GetType().GetMethod("EndPass", new[] { typeof(int) }); // get Delete method from main class instance delete = Instance.GetType().GetMethod("Delete"); // get all public methods and check whether // they can be used as event handlers for glControl var reference = scene.GetValueOrDefault <GLReference>(GraphicControl.nullname); var glControl = (GraphicControl)reference.Reference; var methods = Instance.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); foreach (var method in methods) { var info = glControl.GetType().GetEvent(method.Name); if (info != null) { var csmethod = Delegate.CreateDelegate(info.EventHandlerType, Instance, method.Name); info.AddEventHandler(glControl, csmethod); } } }