using Silk.NET.Maths; using Silk.NET.OpenGL; using System.Numerics; namespace Nebulix.Rendering; public class Shader { private readonly GL _glContext; private readonly uint _shaderProgramId; public Shader(GL openGLContext, string pathToVertexShader, string pathToFragmentShader) { _glContext = openGLContext; var vertexCode = File.ReadAllText(pathToVertexShader); var fragmentCode = File.ReadAllText(pathToFragmentShader); var vertexShader = CompileShader(vertexCode, ShaderType.VertexShader); var fragmentShader = CompileShader(fragmentCode, ShaderType.FragmentShader); _shaderProgramId = CreateProgram(vertexShader, fragmentShader); } public void Use() { _glContext.UseProgram(_shaderProgramId); } #region Set uniforms public void SetInt(string name, int value) { _glContext.Uniform1(_glContext.GetUniformLocation(_shaderProgramId, name), value); } public void SetFloat(string name, float value) { _glContext.Uniform1(_glContext.GetUniformLocation(_shaderProgramId, name), value); } public unsafe void SetMatrix(string name, Matrix4x4 matrix) { _glContext.UniformMatrix4(_glContext.GetUniformLocation(_shaderProgramId, name), 1, false, (float*) &matrix); } public unsafe void SetMatrix(string name, Matrix4X4 matrix) { _glContext.UniformMatrix4(_glContext.GetUniformLocation(_shaderProgramId, name), 1, false, (float*) &matrix); } #endregion /// /// Compiles the given shadercode. /// /// The shadercode /// The type of shader to compile /// Returns the id of the compiled shader. /// protected uint CompileShader(string shaderCode, ShaderType shaderType) { uint shader = _glContext.CreateShader(shaderType); _glContext.ShaderSource(shader, shaderCode); _glContext.CompileShader(shader); _glContext.GetShader(shader, ShaderParameterName.CompileStatus, out int status); if (status != (int)GLEnum.True) throw new ShaderCompileException(shaderType, $"Failed to compile shader with message: \n {_glContext.GetShaderInfoLog(shader)}"); return shader; } /// /// Creates a shader program and links the vertex and fragment shader together. /// /// Returns the id of the created shader program /// protected uint CreateProgram(uint vertexShader, uint fragmentShader) { uint program = _glContext.CreateProgram(); _glContext.AttachShader(program, vertexShader); _glContext.AttachShader(program, fragmentShader); _glContext.LinkProgram(program); _glContext.GetProgram(program, ProgramPropertyARB.LinkStatus, out int lStatus); if (lStatus != (int)GLEnum.True) throw new ShaderLinkException("Error occured while trying to link a shader with message: \n" + _glContext.GetProgramInfoLog(program)); // should be done right after compiling and linking _glContext.DetachShader(program, vertexShader); _glContext.DetachShader(program, fragmentShader); _glContext.DeleteShader(vertexShader); _glContext.DeleteShader(fragmentShader); return program; } }