You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
17 KiB
C#

using System.IO;
using System;
using System.Collections.Generic;
namespace Otter {
/// <summary>
/// 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/
/// </summary>
public class Shader : IDisposable {
#region Static Methods
/// <summary>
/// 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.
/// </summary>
/// <param name="vertexShader">String containing the source code of the vertex shader</param>
/// <param name="fragmentShader">String containing the source code of the fragment shader</param>
/// <returns>New shader instance</returns>
public static SFML.Graphics.Shader FromString(string vertexShader, string fragmentShader)
{
SFML.Graphics.Shader shader = SFML.Graphics.Shader.FromString(vertexShader, fragmentShader);
return shader;
}
/// <summary>
/// Creates a Shader using source code in memory
/// </summary>
/// <param name="shaderType">Type of Shader</param>
/// <param name="shader">GLSL code in memory</param>
/// <returns>New Shader</returns>
public static Shader FromString(ShaderType shaderType, string shader)
{
return (shaderType == ShaderType.Fragment)
? new Shader(FromString(null, shader))
: new Shader(FromString(shader, null));
}
/// <summary>
/// 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.
/// </summary>
/// <example>
/// 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);
/// </example>
/// <param name="name">The Enum value to use as the key for the shader parameter name.</param>
/// <param name="nameInShader">The name of the parameter in the shader code.</param>
public static void AddParameter(Enum name, string nameInShader) {
parameters.Add(Util.EnumValueToString(name), nameInShader);
}
/// <summary>
/// Get the parameter string stored with the Enum key.
/// </summary>
/// <param name="name">The Enum name that is the key for the string parameter.</param>
/// <returns>The string parameter.</returns>
public static string Parameter(Enum name) {
return parameters[Util.EnumValueToString(name)];
}
#endregion
#region Static Fields
static Dictionary<string, string> parameters = new Dictionary<string, string>();
#endregion
#region Constructors
/// <summary>
/// Creates a Shader using a file as the source for the vertex and fragment shader.
/// </summary>
/// <param name="vertexFile">The file path to the vertex shader.</param>
/// <param name="fragmentFile">The file path to the fragment shader.</param>
public Shader(string vertexFile, string fragmentFile) {
SFMLShader = new SFML.Graphics.Shader(Files.LoadFileStream(vertexFile), Files.LoadFileStream(fragmentFile));
}
/// <summary>
/// Create a Shader using a stream as the source of the vertex and fragment shader.
/// </summary>
/// <param name="vertexStream">The stream for the vertex shader.</param>
/// <param name="fragmentStream">The stream for the fragment shader.</param>
public Shader(Stream vertexStream, Stream fragmentStream) {
SFMLShader = new SFML.Graphics.Shader(vertexStream, fragmentStream);
}
/// <summary>
/// Create a shader using a stream as the source and a ShaderType parameter.
/// </summary>
/// <param name="shaderType">The shader type (fragment or vertex)</param>
/// <param name="source">The stream for the shader.</param>
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);
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="source">The file path.</param>
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);
}
}
/// <summary>
/// Creates a shader using a copy of another shader.
/// </summary>
/// <param name="copy">The shader to copy.</param>
public Shader(Shader copy) : this(copy.SFMLShader) { }
/// <summary>
/// Creates a shader using a file path and a ShaderType parameter.
/// </summary>
/// <param name="shaderType">The shader type (fragment or vertex)</param>
/// <param name="source">The file path.</param>
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
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="color">The color to set it to.</param>
public void SetParameter(string name, Color color) {
SFMLShader.SetParameter(name, color.SFMLColor);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="color">The color to set it to.</param>
public void SetParameter(Enum name, Color color) {
SetParameter(Parameter(name), color);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The value to set it to.</param>
public void SetParameter(string name, float x) {
SFMLShader.SetParameter(name, x);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The value to set it to.</param>
public void SetParameter(Enum name, float x) {
SetParameter(Parameter(name), x);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The first value of a vec2.</param>
/// <param name="y">The first value of a vec2.</param>
public void SetParameter(string name, float x, float y) {
SFMLShader.SetParameter(name, x, y);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The first value of a vec2.</param>
/// <param name="y">The first value of a vec2.</param>
public void SetParameter(Enum name, float x, float y) {
SetParameter(Parameter(name), x, y);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="xy">A Vector2 to set.</param>
public void SetParameter(string name, Vector2 xy) {
SFMLShader.SetParameter(name, xy.X, xy.Y);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="xy">A Vector2 to set.</param>
public void SetParameter(Enum name, Vector2 xy) {
SetParameter(Parameter(name), xy.X, xy.Y);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="xyz">A Vector3 to set.</param>
public void SetParameter(string name, Vector3 xyz) {
SFMLShader.SetParameter(name, xyz.X, xyz.Y, xyz.Z);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="xyz">A Vector3 to set.</param>
public void SetParameter(Enum name, Vector3 xyz) {
SetParameter(Parameter(name), xyz.X, xyz.Y, xyz.Z);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="xyzw">A Vector4 to set.</param>
public void SetParameter(string name, Vector4 xyzw) {
SFMLShader.SetParameter(name, xyzw.X, xyzw.Y, xyzw.Z, xyzw.W);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="xyzw">A Vector4 to set.</param>
public void SetParameter(Enum name, Vector4 xyzw) {
SetParameter(Parameter(name), xyzw.X, xyzw.Y, xyzw.Z, xyzw.W);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The first value of a vec3.</param>
/// <param name="y">The second value of a vec3.</param>
/// <param name="z">The third value of a vec3.</param>
public void SetParameter(string name, float x, float y, float z) {
SFMLShader.SetParameter(name, x, y, z);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The first value of a vec3.</param>
/// <param name="y">The second value of a vec3.</param>
/// <param name="z">The third value of a vec3.</param>
public void SetParameter(Enum name, float x, float y, float z) {
SetParameter(Parameter(name), x, y, z);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The first value of a vec4.</param>
/// <param name="y">The second value of a vec4.</param>
/// <param name="z">The third value of a vec4.</param>
/// <param name="w">The fourth value of a vec4.</param>
public void SetParameter(string name, float x, float y, float z, float w) {
SFMLShader.SetParameter(name, x, y, z, w);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="x">The first value of a vec4.</param>
/// <param name="y">The second value of a vec4.</param>
/// <param name="z">The third value of a vec4.</param>
/// <param name="w">The fourth value of a vec4.</param>
public void SetParameter(Enum name, float x, float y, float z, float w) {
SetParameter(Parameter(name), x, y, z, w);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="texture">The texture to set it to.</param>
public void SetParameter(string name, Texture texture) {
SFMLShader.SetParameter(name, texture.SFMLTexture);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="texture">The texture to set it to.</param>
public void SetParameter(Enum name, Texture texture) {
SetParameter(Parameter(name), texture);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="textureSource">The path to an image to load as a texture.</param>
public void SetParameter(string name, string textureSource) {
SFMLShader.SetParameter(name, new Texture(textureSource).SFMLTexture);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="textureSource">The path to an image to load as a texture.</param>
public void SetParameter(Enum name, string textureSource) {
SetParameter(Parameter(name), textureSource);
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="matrix">The matrix to use. SFML internally uses 3x3 matrices, but you need to use a mat4 in the shader.</param>
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));
}
/// <summary>
/// Set a parameter on the shader.
/// </summary>
/// <param name="name">The parameter in the shader to set.</param>
/// <param name="matrix">The matrix to use. SFML internally uses 3x3 matrices, but you need to use a mat4 in the shader.</param>
public void SetParameter(Enum name, Matrix matrix) {
SetParameter(Parameter(name), matrix);
}
/// <summary>
/// Disposes the shader to probably clear up memory.
/// </summary>
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;
}
/// <summary>
/// For when the garbage collector destroys shaders, also
/// free up the memory on the video card that the shader is using.
/// </summary>
~Shader() {
Dispose();
}
#endregion
}
#region Enum
public enum ShaderType {
Vertex,
Fragment
}
#endregion
}