using System.Numerics; using Silk.NET.OpenGL; namespace AcDream.App.Rendering; public sealed class Shader : IDisposable { private readonly GL _gl; public uint Program { get; } public Shader(GL gl, string vertexPath, string fragmentPath) { _gl = gl; uint vert = Compile(File.ReadAllText(vertexPath), ShaderType.VertexShader); uint frag = Compile(File.ReadAllText(fragmentPath), ShaderType.FragmentShader); Program = _gl.CreateProgram(); _gl.AttachShader(Program, vert); _gl.AttachShader(Program, frag); _gl.LinkProgram(Program); _gl.GetProgram(Program, ProgramPropertyARB.LinkStatus, out int linked); if (linked == 0) throw new Exception("program link failed: " + _gl.GetProgramInfoLog(Program)); _gl.DetachShader(Program, vert); _gl.DetachShader(Program, frag); _gl.DeleteShader(vert); _gl.DeleteShader(frag); } private uint Compile(string source, ShaderType type) { uint id = _gl.CreateShader(type); _gl.ShaderSource(id, source); _gl.CompileShader(id); _gl.GetShader(id, ShaderParameterName.CompileStatus, out int ok); if (ok == 0) throw new Exception($"{type} compile failed: " + _gl.GetShaderInfoLog(id)); return id; } public void Use() => _gl.UseProgram(Program); public unsafe void SetMatrix4(string name, Matrix4x4 m) { int loc = _gl.GetUniformLocation(Program, name); _gl.UniformMatrix4(loc, 1, false, (float*)&m); } public void SetInt(string name, int value) { int loc = _gl.GetUniformLocation(Program, name); _gl.Uniform1(loc, value); } public void SetFloat(string name, float value) { int loc = _gl.GetUniformLocation(Program, name); _gl.Uniform1(loc, value); } public void SetVec3(string name, Vector3 v) { int loc = _gl.GetUniformLocation(Program, name); _gl.Uniform3(loc, v.X, v.Y, v.Z); } public void SetVec2(string name, Vector2 v) { int loc = _gl.GetUniformLocation(Program, name); _gl.Uniform2(loc, v.X, v.Y); } public void SetVec4(string name, Vector4 v) { int loc = _gl.GetUniformLocation(Program, name); _gl.Uniform4(loc, v.X, v.Y, v.Z, v.W); } public void Dispose() => _gl.DeleteProgram(Program); }