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; } }
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); }
public Shader(ShaderObject singleShaderProgram) : this() { Attach(singleShaderProgram); Link(); }
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); }