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
}