using System.IO; using System; using System.Collections.Generic; namespace Otter { /// /// Class representing a shader written in GLSL. /// Warning: Visual Studio encoding must be set to Western European (Windows) Codepage 1252 when editing shaders! /// More details here: http://blog.pixelingene.com/2008/07/file-encodings-matter-when-writing-pixel-shaders/ /// public class Shader : IDisposable { #region Static Methods /// /// Load both the vertex and fragment shaders from source codes in memory /// /// This function can load both the vertex and the fragment /// shaders, or only one of them: pass NULL if you don't want to load /// either the vertex shader or the fragment shader. /// The sources must be valid shaders in GLSL language. GLSL is /// a C-like language dedicated to OpenGL shaders; you'll /// probably need to read a good documentation for it before /// writing your own shaders. /// /// String containing the source code of the vertex shader /// String containing the source code of the fragment shader /// New shader instance public static SFML.Graphics.Shader FromString(string vertexShader, string fragmentShader) { SFML.Graphics.Shader shader = SFML.Graphics.Shader.FromString(vertexShader, fragmentShader); return shader; } /// /// Creates a Shader using source code in memory /// /// Type of Shader /// GLSL code in memory /// New Shader public static Shader FromString(ShaderType shaderType, string shader) { return (shaderType == ShaderType.Fragment) ? new Shader(FromString(null, shader)) : new Shader(FromString(shader, null)); } /// /// Store a shader parameter name by an Enum value. After storing a parameter this way /// you can use SetParameter on shader instances with the Enum value and it will retrieve /// the parameter name string. /// /// /// If your shader has a parameter named "overlayColor" you can do this: /// Shader.SetParameter(ShaderParams.OverlayColor, "overlayColor"); /// And then on a shader instance you can do this: /// someImageWithAShader.Shader.SetParameter(ShaderParams.OverlayColor, Color.Red); /// /// The Enum value to use as the key for the shader parameter name. /// The name of the parameter in the shader code. public static void AddParameter(Enum name, string nameInShader) { parameters.Add(Util.EnumValueToString(name), nameInShader); } /// /// Get the parameter string stored with the Enum key. /// /// The Enum name that is the key for the string parameter. /// The string parameter. public static string Parameter(Enum name) { return parameters[Util.EnumValueToString(name)]; } #endregion #region Static Fields static Dictionary parameters = new Dictionary(); #endregion #region Constructors /// /// Creates a Shader using a file as the source for the vertex and fragment shader. /// /// The file path to the vertex shader. /// The file path to the fragment shader. public Shader(string vertexFile, string fragmentFile) { SFMLShader = new SFML.Graphics.Shader(Files.LoadFileStream(vertexFile), Files.LoadFileStream(fragmentFile)); } /// /// Create a Shader using a stream as the source of the vertex and fragment shader. /// /// The stream for the vertex shader. /// The stream for the fragment shader. public Shader(Stream vertexStream, Stream fragmentStream) { SFMLShader = new SFML.Graphics.Shader(vertexStream, fragmentStream); } /// /// Create a shader using a stream as the source and a ShaderType parameter. /// /// The shader type (fragment or vertex) /// The stream for the shader. public Shader(ShaderType shaderType, Stream source) { if (shaderType == ShaderType.Vertex) { SFMLShader = new SFML.Graphics.Shader(source, null); } else { SFMLShader = new SFML.Graphics.Shader(null, source); } } /// /// Creates a Shader using a file path source, and auto detects which type of shader /// it is. If the file path contains ".frag" or ".fs" it is assumed to be a fragment shader. /// /// The file path. public Shader(string source) { var str = System.Text.Encoding.Default.GetString(Files.LoadFileBytes(source)); if (source.Contains(".frag") || source.Contains(".fs")) { SFMLShader = SFML.Graphics.Shader.FromString(null, str); } else { SFMLShader = new SFML.Graphics.Shader(str, null); } } /// /// Creates a shader using a copy of another shader. /// /// The shader to copy. public Shader(Shader copy) : this(copy.SFMLShader) { } /// /// Creates a shader using a file path and a ShaderType parameter. /// /// The shader type (fragment or vertex) /// The file path. public Shader(ShaderType shaderType, string source) { if (shaderType == ShaderType.Vertex) { SFMLShader = new SFML.Graphics.Shader(source, null); } else { SFMLShader = new SFML.Graphics.Shader(null, source); } } #endregion #region Public Properties public bool IsDisposed { get; private set; } #endregion #region Public Methods /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The color to set it to. public void SetParameter(string name, Color color) { SFMLShader.SetParameter(name, color.SFMLColor); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The color to set it to. public void SetParameter(Enum name, Color color) { SetParameter(Parameter(name), color); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The value to set it to. public void SetParameter(string name, float x) { SFMLShader.SetParameter(name, x); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The value to set it to. public void SetParameter(Enum name, float x) { SetParameter(Parameter(name), x); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The first value of a vec2. /// The first value of a vec2. public void SetParameter(string name, float x, float y) { SFMLShader.SetParameter(name, x, y); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The first value of a vec2. /// The first value of a vec2. public void SetParameter(Enum name, float x, float y) { SetParameter(Parameter(name), x, y); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// A Vector2 to set. public void SetParameter(string name, Vector2 xy) { SFMLShader.SetParameter(name, xy.X, xy.Y); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// A Vector2 to set. public void SetParameter(Enum name, Vector2 xy) { SetParameter(Parameter(name), xy.X, xy.Y); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// A Vector3 to set. public void SetParameter(string name, Vector3 xyz) { SFMLShader.SetParameter(name, xyz.X, xyz.Y, xyz.Z); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// A Vector3 to set. public void SetParameter(Enum name, Vector3 xyz) { SetParameter(Parameter(name), xyz.X, xyz.Y, xyz.Z); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// A Vector4 to set. public void SetParameter(string name, Vector4 xyzw) { SFMLShader.SetParameter(name, xyzw.X, xyzw.Y, xyzw.Z, xyzw.W); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// A Vector4 to set. public void SetParameter(Enum name, Vector4 xyzw) { SetParameter(Parameter(name), xyzw.X, xyzw.Y, xyzw.Z, xyzw.W); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The first value of a vec3. /// The second value of a vec3. /// The third value of a vec3. public void SetParameter(string name, float x, float y, float z) { SFMLShader.SetParameter(name, x, y, z); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The first value of a vec3. /// The second value of a vec3. /// The third value of a vec3. public void SetParameter(Enum name, float x, float y, float z) { SetParameter(Parameter(name), x, y, z); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The first value of a vec4. /// The second value of a vec4. /// The third value of a vec4. /// The fourth value of a vec4. public void SetParameter(string name, float x, float y, float z, float w) { SFMLShader.SetParameter(name, x, y, z, w); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The first value of a vec4. /// The second value of a vec4. /// The third value of a vec4. /// The fourth value of a vec4. public void SetParameter(Enum name, float x, float y, float z, float w) { SetParameter(Parameter(name), x, y, z, w); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The texture to set it to. public void SetParameter(string name, Texture texture) { SFMLShader.SetParameter(name, texture.SFMLTexture); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The texture to set it to. public void SetParameter(Enum name, Texture texture) { SetParameter(Parameter(name), texture); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The path to an image to load as a texture. public void SetParameter(string name, string textureSource) { SFMLShader.SetParameter(name, new Texture(textureSource).SFMLTexture); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The path to an image to load as a texture. public void SetParameter(Enum name, string textureSource) { SetParameter(Parameter(name), textureSource); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The matrix to use. SFML internally uses 3x3 matrices, but you need to use a mat4 in the shader. public void SetParameter(string name, Matrix matrix) { SFMLShader.SetParameter(name, new SFML.Graphics.Transform(matrix.M11, matrix.M12, matrix.M13, matrix.M21, matrix.M22, matrix.M23, matrix.M31, matrix.M32, matrix.M33)); } /// /// Set a parameter on the shader. /// /// The parameter in the shader to set. /// The matrix to use. SFML internally uses 3x3 matrices, but you need to use a mat4 in the shader. public void SetParameter(Enum name, Matrix matrix) { SetParameter(Parameter(name), matrix); } /// /// Disposes the shader to probably clear up memory. /// public void Dispose() { if (SFMLShader == null) return; if (!IsDisposed) { SFMLShader.Dispose(); IsDisposed = true; } } #endregion #region Internal internal SFML.Graphics.Shader SFMLShader; internal Shader(SFML.Graphics.Shader shader) { this.SFMLShader = shader; } /// /// For when the garbage collector destroys shaders, also /// free up the memory on the video card that the shader is using. /// ~Shader() { Dispose(); } #endregion } #region Enum public enum ShaderType { Vertex, Fragment } #endregion }