예제 #1
0
        public void Attach(ShaderObject shaderObj)
        {
            if (Disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }
            if (shaderObj.Disposed)
            {
                throw new ObjectDisposedException(shaderObj.GetType().FullName);
            }

            if (shaderObj is VertexShader)
            {
                m_VertexShader = (VertexShader)shaderObj;
            }
            else if (shaderObj is FragmentShader)
            {
                m_FragmentShader = (FragmentShader)shaderObj;
            }

            GL.AttachObject(m_Id, shaderObj.Id);

            if (m_UniformLocations != null)
            {
                m_UniformLocations.Clear();
            }

            // TODO: optimize so that there would not be more than one uniform with the same name in the list
            if (shaderObj.StaticAutoUniforms != null)
            {
                if (StaticAutoUniforms == null)
                {
                    StaticAutoUniforms = new List <ShaderAutoUniformInfo>();
                }
                StaticAutoUniforms.AddRange(shaderObj.StaticAutoUniforms);
            }
            if (shaderObj.DynamicAutoUniforms != null)
            {
                if (DynamicAutoUniforms == null)
                {
                    DynamicAutoUniforms = new List <ShaderAutoUniformInfo>();
                }
                DynamicAutoUniforms.AddRange(shaderObj.DynamicAutoUniforms);
            }
            if (m_Version == null || m_Version < shaderObj.Version)
            {
                m_Version = shaderObj.Version;
            }
        }
예제 #2
0
        public static Shader Load(DomNode node, string fileName)
        {
            foreach (DomAttribute attr in node.Attributes)
            {
                switch (attr.Name.ToLower())
                {
                case "src": return(Load(attr.Value.ToPath()));

                case "relsrc": return(Load(attr.Value.RelativeTo(fileName)));
                }
            }

            List <ShaderObject> objectsToAttach = new List <ShaderObject>();

            foreach (DomNode child in node)
            {
                switch (child.Name.ToLower())
                {
                case "shader":
                    ShaderObject sobj = ShaderObject.Load(child, fileName);
                    // GameDebugger.Log("Loaded {0}", sobj.GetType().Name);
                    if (sobj == null)
                    {
                        foreach (ShaderObject shaderObj in objectsToAttach)
                        {
                            shaderObj.Dispose();
                        }
                        return(null);                                // shader program has a component that requires GLSL version that is higher than currently available or there was no code present
                    }
                    objectsToAttach.Add(sobj);
                    break;
                }
            }

            Shader obj = new Shader();

            foreach (ShaderObject shaderObj in objectsToAttach)
            {
                obj.Attach(shaderObj);
            }
            obj.Link();

            return(obj);
        }
예제 #3
0
 public Shader(ShaderObject singleShaderProgram) : this()
 {
     Attach(singleShaderProgram);
     Link();
 }
예제 #4
0
        public static ShaderObject Load(DomNode node, string fileName)
        {
            int[]        intVal   = new int[4];
            float[]      floatVal = new float[4];
            string[]     splitValue;
            string       shaderTypeString = null;
            ShaderObject obj = null;
            Version      ver, maxVer = Shader.VersionSupported;

            Version bestVersion = null;
            DomNode bestNode    = null;

            List <ShaderAutoUniformInfo> StaticAutoUniforms  = null;
            List <ShaderAutoUniformInfo> DynamicAutoUniforms = null;
            string code = null;

            foreach (DomAttribute attr in node.Attributes)
            {
                switch (attr.Name.ToLower())
                {
                case "src":  return(Load(attr.Value.ToPath()));

                case "relsrc": return(Load(attr.Value.RelativeTo(fileName)));

                case "type": shaderTypeString = attr.Value.ToLower(); break;
                }
            }

            foreach (DomNode child in node)
            {
                if (child.Name.ToLower().Equals("content"))
                {
                    if (!Version.TryParse(child["version"], out ver))
                    {
                        ver = new Version("0.0");
                    }
                    if ((bestVersion == null || bestVersion < ver) && ver <= maxVer)
                    {
                        bestNode    = child;
                        bestVersion = ver;
                    }
                }
            }

            if (bestNode == null)
            {
                return(null);
            }

            foreach (DomNode child in bestNode)
            {
                switch (child.Name.ToLower())
                {
                case "code":
                    code = child.Value;
                    break;

                case "uniform":
                    ShaderAutoUniformInfo aui = new ShaderAutoUniformInfo(null, ShaderAutoUniformClass.Unknown, null);
                    bool typePresent          = false;
                    foreach (DomAttribute attr in child.Attributes)
                    {
                        switch (attr.Name)
                        {
                        case "name":
                            aui.Name = attr.Value;
                            break;

                        case "type":
                            typePresent = true;
                            if (attr.Value.ToLower() == "unknown" || !ShaderAutoUniformClass.TryParse(attr.Value, true, out aui.Type))
                            {
                                aui.Type = ShaderAutoUniformClass.Unknown;
                                // This is not a critical error, but it will affect how shader will work during render process so we have to log this minor error
                                GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform with an unexpected type of '{1}'", fileName, attr.Value);
                            }
                            break;

                        case "value":
                            aui.Value = attr.Value;
                            break;
                        }
                    }

                    if (!typePresent || aui.Name == null || aui.Name.Equals(""))
                    {
                        GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' that does not have all required attributes", fileName, aui.Name);
                    }
                    else if (aui.Type != ShaderAutoUniformClass.Unknown)
                    {
                        if (aui.Value == null)
                        {
                            if (aui.Type == ShaderAutoUniformClass.GameTime || aui.Type == ShaderAutoUniformClass.NonStopTime)
                            {
                                aui.Value = "1";
                            }
                            else
                            {
                                GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' that has no value set", fileName, aui.Name);
                            }
                        }
                        bool result = false;

                        if (aui.Value != null)
                        {
                            switch (aui.Type)
                            {
                            case ShaderAutoUniformClass.Int:
                                if (result = int.TryParse((string)aui.Value, out intVal[0]))
                                {
                                    aui.Value = intVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.Float:
                                if (result = float.TryParse((string)aui.Value, out floatVal[0]))
                                {
                                    aui.Value = floatVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.Vec2:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 2)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = float.TryParse(splitValue[0], out floatVal[0]))
                                    {
                                        if (result = float.TryParse(splitValue[1], out floatVal[1]))
                                        {
                                            aui.Value = new Vector2(floatVal[0], floatVal[1]);
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Vec3:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 3)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = float.TryParse(splitValue[0], out floatVal[0]))
                                    {
                                        if (result = float.TryParse(splitValue[1], out floatVal[1]))
                                        {
                                            if (result = float.TryParse(splitValue[2], out floatVal[2]))
                                            {
                                                aui.Value = new Vector3(floatVal[0], floatVal[1], floatVal[2]);
                                            }
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Vec4:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 4)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = float.TryParse(splitValue[0], out floatVal[0]))
                                    {
                                        if (result = float.TryParse(splitValue[1], out floatVal[1]))
                                        {
                                            if (result = float.TryParse(splitValue[2], out floatVal[2]))
                                            {
                                                if (result = float.TryParse(splitValue[3], out floatVal[3]))
                                                {
                                                    aui.Value = new Vector4(floatVal[0], floatVal[1], floatVal[2], floatVal[3]);
                                                }
                                            }
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Point2:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 2)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = int.TryParse(splitValue[0], out intVal[0]))
                                    {
                                        if (result = int.TryParse(splitValue[1], out intVal[1]))
                                        {
                                            aui.Value = new Point2(intVal[0], intVal[1]);
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Point3:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 3)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = int.TryParse(splitValue[0], out intVal[0]))
                                    {
                                        if (result = int.TryParse(splitValue[1], out intVal[1]))
                                        {
                                            if (result = int.TryParse(splitValue[2], out intVal[2]))
                                            {
                                                aui.Value = new Point3(intVal[0], intVal[1], intVal[2]);
                                            }
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Point4:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 4)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = int.TryParse(splitValue[0], out intVal[0]))
                                    {
                                        if (result = int.TryParse(splitValue[1], out intVal[1]))
                                        {
                                            if (result = int.TryParse(splitValue[2], out intVal[2]))
                                            {
                                                if (result = int.TryParse(splitValue[3], out intVal[3]))
                                                {
                                                    aui.Value = new Point4(intVal[0], intVal[1], intVal[2], intVal[3]);
                                                }
                                            }
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Color4:
                                splitValue = ((string)aui.Value).Split(',');
                                if (splitValue.Length != 4)
                                {
                                    GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value for '{2}' type", fileName, aui.Name, aui.Type);
                                }
                                else
                                {
                                    if (result = float.TryParse(splitValue[0], out floatVal[0]))
                                    {
                                        if (result = float.TryParse(splitValue[1], out floatVal[1]))
                                        {
                                            if (result = float.TryParse(splitValue[2], out floatVal[2]))
                                            {
                                                if (result = float.TryParse(splitValue[3], out floatVal[3]))
                                                {
                                                    aui.Value = new Color4(floatVal[0], floatVal[1], floatVal[2], floatVal[3]);
                                                }
                                            }
                                        }
                                    }
                                }
                                break;

                            case ShaderAutoUniformClass.Sampler1D:
                                if (result = int.TryParse((string)aui.Value, out intVal[0]))
                                {
                                    aui.Value = intVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.Sampler2D:
                                if (result = int.TryParse((string)aui.Value, out intVal[0]))
                                {
                                    aui.Value = intVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.Sampler3D:
                                if (result = int.TryParse((string)aui.Value, out intVal[0]))
                                {
                                    aui.Value = intVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.Sampler4D:
                                if (result = int.TryParse((string)aui.Value, out intVal[0]))
                                {
                                    aui.Value = intVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.NonStopTime:
                                if (result = float.TryParse((string)aui.Value, out floatVal[0]))
                                {
                                    aui.Value = floatVal[0];
                                }
                                break;

                            case ShaderAutoUniformClass.GameTime:
                                if (result = float.TryParse((string)aui.Value, out floatVal[0]))
                                {
                                    aui.Value = floatVal[0];
                                }
                                break;

                            default:
                                GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with a type that is not fully implemented yet (no parser for the value)", fileName, aui.Name);
                                break;
                            }
                        }

                        if (result)
                        {
                            if (aui.Type == ShaderAutoUniformClass.GameTime || aui.Type == ShaderAutoUniformClass.NonStopTime)
                            {
                                if (DynamicAutoUniforms == null)
                                {
                                    DynamicAutoUniforms = new List <ShaderAutoUniformInfo>();
                                }
                                DynamicAutoUniforms.Add(aui);
                            }
                            else
                            {
                                if (StaticAutoUniforms == null)
                                {
                                    StaticAutoUniforms = new List <ShaderAutoUniformInfo>();
                                }
                                StaticAutoUniforms.Add(aui);
                            }
                        }
                        else
                        {
                            GameDebugger.Log(LogLevel.Error, "Shader object '{0}' has an auto uniform '{1}' with an invalid value", fileName, aui.Name);
                        }
                    }

                    break;
                }
            }

            if (code == null)
            {
                return(null);
            }

            switch (shaderTypeString)
            {
            case "vertex": obj = new VertexShader(); break;

            case "fragment": obj = new FragmentShader(); break;

            default: throw new UserFriendlyException(String.Format("Shader node in '{1}' has a type attribute with an unrecognizable value '{0}' while only 'vertex' and 'fragment' are supported.", shaderTypeString, fileName), "There was an error in one of shader definition files.");
            }

            obj.m_Version = bestVersion;
            obj.SetSource(code);
            obj.Compile();
            obj.StaticAutoUniforms  = StaticAutoUniforms;
            obj.DynamicAutoUniforms = DynamicAutoUniforms;

            return(obj);
        }