using System; using System.IO; using System.Numerics; using System.Text; using System.Text.RegularExpressions; using static OpenGL.GL; namespace OpenGLTutorial.Rendering.Shaders { public class Shader { private readonly string _vertexCode; private readonly string _fragmentCode; private bool _loaded = false; public uint Program { get; private set; } public Shader(string vertexPath, string fragmentPath) { using (var vertexReader = new StreamReader(vertexPath, Encoding.UTF8)) _vertexCode = vertexReader.ReadToEnd(); using (var fragmentReader = new StreamReader(fragmentPath, Encoding.UTF8)) _fragmentCode = fragmentReader.ReadToEnd(); } public Shader(string shader, bool isFile = true) { using var reader = isFile ? new StreamReader(shader, Encoding.UTF8) : null; string source = isFile ? reader.ReadToEnd() : shader; string[] splitString = Regex.Split(source, "(#type [a-zA-Z]+)"); string firstPattern = splitString[1].Replace("#type ", "").Trim(); string secondPattern = splitString[3].Replace("#type ", "").Trim(); if (firstPattern.ToLower().Equals("vertex")) _vertexCode = splitString[2]; else if (firstPattern.ToLower().Equals("fragment")) _fragmentCode = splitString[2]; else throw new IOException("Unexpected token '" + firstPattern + "' in '" + shader + "'"); if (secondPattern.ToLower().Equals("vertex")) _vertexCode = splitString[4]; else if (secondPattern.ToLower().Equals("fragment")) _fragmentCode = splitString[4]; else throw new IOException("Unexpected token '" + secondPattern + "' in '" + shader + "'"); } public void Load() { if (_loaded) return; _loaded = true; uint vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, _vertexCode); glCompileShader(vs); int[] status = glGetShaderiv(vs, GL_COMPILE_STATUS, 1); if (status[0] == 0) { string error = glGetShaderInfoLog(vs); throw new Exception("Error compiling vertex shader: " + error); } uint fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, _fragmentCode); glCompileShader(fs); status = glGetShaderiv(fs, GL_COMPILE_STATUS, 1); if (status[0] == 0) { string error = glGetShaderInfoLog(fs); throw new Exception("Error compiling fragment shader: " + error); } Program = glCreateProgram(); glAttachShader(Program, vs); glAttachShader(Program, fs); glLinkProgram(Program); glDetachShader(Program, vs); glDetachShader(Program, fs); glDeleteShader(vs); glDeleteShader(fs); } public void Use() { glUseProgram(Program); } public void Delete() { glUseProgram(0); glDeleteProgram(Program); } public void SetMatrix4X4(string uniformName, Matrix4x4 matrix) { int location = glGetUniformLocation(Program, uniformName); glUniformMatrix4fv(location, 1, false, GetMatrix4X4Values(matrix)); } private float[] GetMatrix4X4Values(Matrix4x4 m) { return new [] { m.M11, m.M12, m.M13, m.M14, m.M21, m.M22, m.M23, m.M24, m.M31, m.M32, m.M33, m.M34, m.M41, m.M42, m.M43, m.M44 }; } } }