Example #1
0
        private void CompileShader(Retyped.dom.WebGLShader shader, string source)
        {
            // Populate the shader and compile it
            GL.shaderSource(shader, source);
            GL.compileShader(shader);

            // Check for shader compile errors
            bool status = (bool)GL.getShaderParameter(shader, GL.COMPILE_STATUS);

            if (!status)
            {
                throw new CKGLException("Shader compile error: " + GL.getShaderInfoLog(shader));
            }
        }
Example #2
0
        private void Compile(string source)
        {
            int vertex   = source.IndexOf("#vertex", StringComparison.Ordinal);
            int geometry = source.IndexOf("#geometry", StringComparison.Ordinal);
            int fragment = source.IndexOf("#fragment", StringComparison.Ordinal);

            if (vertex == -1)
            {
                throw new CKGLException("Shader source must contain a vertex shader definition.");
            }

            bool hasGeometryDefinition = geometry != -1;
            bool hasFragmentDefinition = fragment != -1;

            if (geometry != -1)
            {
                throw new CKGLException("WebGL 2.0 does not support Geometry Shaders.");
            }

            string vertSource = hasGeometryDefinition
                                                                ? source.Substring(vertex, geometry - vertex)
                                                                : hasFragmentDefinition
                                                                        ? source.Substring(vertex, fragment - vertex)
                                                                        : source.Substring(vertex);

            //string geomSource = hasGeometryDefinition
            //					? hasFragmentDefinition
            //						? source.Substring(geometry, fragment - geometry)
            //						: source.Substring(geometry)
            //					: "";
            string fragSource = hasFragmentDefinition
                                                                ? source.Substring(fragment)
                                                                : "";

            // Debug
            //Output.WriteLine($"\nVertex Shader:\n{vertSource}");
            //Output.WriteLine($"\nGeometry Shader:\n{geomSource}");
            //Output.WriteLine($"\nFragment Shader:\n{fragSource}");

            // Create the shaders and compile them
            Retyped.dom.WebGLShader vertID = GL.createShader(GL.VERTEX_SHADER);
            //Output.WriteLine(vertSource.Replace("#vertex", ShaderIncludes.Vertex));
            CompileShader(vertID, ConvertVertex(vertSource.Replace("#vertex", ShaderIncludes.Vertex)));

            //Retyped.dom.WebGLShader geomID = null;
            //if (hasGeometryDefinition)
            //{
            //	geomID = GL.createShader(GL.GEOMETRY_SHADER);
            //	//Output.WriteLine(geomSource.Replace("#geometry", ShaderIncludes.Geometry));
            //	CompileShader(geomID, ConvertGeometry(geomSource.Replace("#geometry", ShaderIncludes.Geometry)));
            //}

            Retyped.dom.WebGLShader fragID = null;
            if (hasFragmentDefinition)
            {
                fragID = GL.createShader(GL.FRAGMENT_SHADER);
                //Output.WriteLine(fragSource.Replace("#fragment", ShaderIncludes.Fragment));
                CompileShader(fragID, ConvertFragment(fragSource.Replace("#fragment", ShaderIncludes.Fragment)));
            }

            // Create the program and attach the shaders to it
            shader = GL.createProgram();
            GL.attachShader(shader, vertID);
            //if (hasGeometryDefinition)
            //	GL.attachShader(shader, geomID);
            if (hasFragmentDefinition)
            {
                GL.attachShader(shader, fragID);
            }

            // WebGL 1.0 only - Automatically bind attributes based on layout qualifiers
            try
            {
                string[] lines = vertSource.Split('\n');

                for (int i = 0; i < lines.Length; i++)
                {
                    if (lines[i].Contains("layout(location") && (lines[i].Contains("in ") || lines[i].Contains("attribute ")))
                    {
                        string[] line     = lines[i].Replace("layout(location =", "").Replace("layout(location=", "").Replace(";", " ").Trim().Split(' ');
                        int      attribID = int.Parse(line[0].Substring(0, line[0].Length - 1).Trim());
                        string   name     = line[3].Trim();
                        //Output.WriteLine($"Shader - Bind Attribute | id: {attribID}, {name} ({line[2]})"); // Debug
                        GL.bindAttribLocation(shader, attribID, name);
                    }
                }
            }
            catch (Exception e)
            {
                Output.WriteLine($"WebGL 1.0 - Automatic Shader Attribute binding failed: {e.Message}");
            }

            // Link the program and check for errors
            GL.linkProgram(shader);
            bool linkStatus = (bool)GL.getProgramParameter(shader, GL.LINK_STATUS);

            if (!linkStatus)
            {
                throw new CKGLException("Program link error: " + GL.getProgramInfoLog(shader));
            }

            // Validate the program and check for errors
            GL.validateProgram(shader);
            bool validateStatus = (bool)GL.getProgramParameter(shader, GL.VALIDATE_STATUS);

            if (!validateStatus)
            {
                throw new CKGLException("Program validate error: " + GL.getProgramInfoLog(shader));
            }

            // Once linked, we can detach and delete the shaders
            GL.detachShader(shader, vertID);
            GL.deleteShader(vertID);
            //if (hasGeometryDefinition)
            //{
            //	GL.detachShader(shader, geomID);
            //	GL.deleteShader(geomID);
            //}
            if (hasFragmentDefinition)
            {
                GL.detachShader(shader, fragID);
                GL.deleteShader(fragID);
            }

            // Get all the uniforms the shader has and store their information
            int numUniforms = (int)GL.getProgramParameter(shader, GL.ACTIVE_UNIFORMS);

            for (int i = 0; i < numUniforms; ++i)
            {
                var    uniformInfo = GL.getActiveUniform(shader, i);
                string name        = uniformInfo.name;
                uint   type        = uniformInfo.type;
                int    count       = uniformInfo.size;
                if (count > 0 && name != null)
                {
                    if (count > 1)
                    {
                        name = name.Substring(0, name.LastIndexOf('['));
                        string arrName;
                        for (int n = 0; n < count; ++n)
                        {
                            arrName = $"{name}[{n}]";
                            WebGLUniformLocation loc = GL.getUniformLocation(shader, arrName);
                            //Output.WriteLine($"index:{i} name:{arrName} type:{type} loc:{loc} count:{count}");
                            var uniform = new Uniform(i, arrName, type, loc);
                            uniforms.Add(arrName, uniform);
                        }
                    }
                    else
                    {
                        WebGLUniformLocation loc = GL.getUniformLocation(shader, name);
                        //Output.WriteLine($"index:{i} name:{name} type:{type} loc:{loc} count:{count}");
                        var uniform = new Uniform(i, name, type, loc);
                        uniforms.Add(name, uniform);
                    }
                }
            }
        }