Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
        /// <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));
        }
Exemplo n.º 3
0
        /// <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;
            }
        }
Exemplo n.º 4
0
 /// <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);
     }
 }
Exemplo n.º 5
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));
            }
        }
Exemplo n.º 6
0
        /// <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);
        }
Exemplo n.º 7
0
        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);
            }
        }
Exemplo n.º 8
0
        /// <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;
            }
        }
Exemplo n.º 9
0
        /// <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 });
        }
Exemplo n.º 10
0
        /// <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);
        }
Exemplo n.º 11
0
        /// <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);
        }
Exemplo n.º 12
0
        /// <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));
        }
Exemplo n.º 13
0
        /// <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));
        }
Exemplo n.º 14
0
        /// <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);
        }
Exemplo n.º 15
0
            /// <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);
            }
Exemplo n.º 16
0
        /// <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());
        }
Exemplo n.º 17
0
        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);
        }
Exemplo n.º 18
0
        /// <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);
        }
Exemplo n.º 19
0
        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));
            }
        }
Exemplo n.º 20
0
        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));
        }
Exemplo n.º 21
0
        /// <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;
            }
        }
Exemplo n.º 22
0
 public static CompileException Add(this CompileException err, string message,
                                    Compiler.Command cmd)
 {
     return(err.Add(message, cmd.File, cmd.LineInFile));
 }
Exemplo n.º 23
0
 public static CompileException Add(this CompileException err, string message,
                                    Compiler.Block block)
 {
     return(err.Add(message, block.Filename, block.LineInFile));
 }
Exemplo n.º 24
0
        /// <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;
            }
        }
Exemplo n.º 25
0
        /// <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);
        }
Exemplo n.º 26
0
        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);
        }
Exemplo n.º 27
0
        /// <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,
            });
        }