using System.Numerics; using Silk.NET.OpenGL; namespace AcDream.App.Rendering; public sealed class Shader : IDisposable { private readonly GL _gl; private readonly Dictionary _uniformLocations = new(StringComparer.Ordinal); public uint Program { get; private set; } public Shader(GL gl, string vertexPath, string fragmentPath) { _gl = gl; string vertexSource = File.ReadAllText(vertexPath); string fragmentSource = File.ReadAllText(fragmentPath); Program = ShaderProgramConstruction.Build( new GlShaderProgramBuildApi(gl), vertexSource, fragmentSource); } public void Use() => _gl.UseProgram(Program); public unsafe void SetMatrix4(string name, Matrix4x4 m) { int loc = GetUniformLocation(name); _gl.UniformMatrix4(loc, 1, false, (float*)&m); } public void SetInt(string name, int value) { int loc = GetUniformLocation(name); _gl.Uniform1(loc, value); } public void SetFloat(string name, float value) { int loc = GetUniformLocation(name); _gl.Uniform1(loc, value); } public void SetVec3(string name, Vector3 v) { int loc = GetUniformLocation(name); _gl.Uniform3(loc, v.X, v.Y, v.Z); } public void SetVec2(string name, Vector2 v) { int loc = GetUniformLocation(name); _gl.Uniform2(loc, v.X, v.Y); } public void SetVec4(string name, Vector4 v) { int loc = GetUniformLocation(name); _gl.Uniform4(loc, v.X, v.Y, v.Z, v.W); } private int GetUniformLocation(string name) { ArgumentException.ThrowIfNullOrWhiteSpace(name); if (_uniformLocations.TryGetValue(name, out int location)) return location; location = _gl.GetUniformLocation(Program, name); _uniformLocations.Add(name, location); return location; } public void Dispose() { uint program = Program; if (program == 0) return; _uniformLocations.Clear(); GlResourceCommand.DeleteProgram(_gl, program, $"delete Shader program {program}"); Program = 0; } }