using System; using System.IO; using System.Reflection; using Quik.OpenGL; using static Quik.OpenGL.GLEnum; namespace Quik.OpenTK { public class GL30Driver : IDisposable { public GL30Driver() { Assembly asm = typeof(GL30Driver).Assembly; using (StreamReader vert = new StreamReader(asm.GetManifestResourceStream("Quik.OpenTK.glsl.glsl130.vert"))) using (StreamReader frag = new StreamReader(asm.GetManifestResourceStream("Quik.OpenTK.glsl.glsl130.frag"))) { int vs; int fs; vs = GL.CreateShader(GL_VERTEX_SHADER); fs = GL.CreateShader(GL_FRAGMENT_SHADER); _sp = GL.CreateProgram(); GL.ShaderSource(vs, vert.ReadToEnd()); GL.ShaderSource(fs, frag.ReadToEnd()); GL.CompileShader(vs); GL.CompileShader(fs); #if DEBUG int status; GL.GetShader(vs, GL_COMPILE_STATUS, out status); if (status == 0) { throw new Exception(GL.GetShaderInfoLog(vs)); } GL.GetShader(fs, GL_COMPILE_STATUS, out status); if (status == 0) { throw new Exception(GL.GetShaderInfoLog(fs)); } #endif GL.AttachShader(_sp, vs); GL.AttachShader(_sp, fs); GL.LinkProgram(_sp); #if DEBUG GL.GetProgram(_sp, GL_LINK_STATUS, out status); if (status == 0) { throw new Exception(GL.GetProgramInfoLog(_sp)); } #endif GL.DetachShader(_sp, vs); GL.DetachShader(_sp, fs); GL.DeleteShader(vs); GL.DeleteShader(fs); } LoadUniform(_nameM4View, out _locM4View); LoadUniform(_nameM4Model, out _locM4Model); LoadUniform(_nameIFlags, out _locIFlags); LoadUniform(_nameFSdfThreshold, out _locFSdfThreshold); LoadUniform(_nameFSdfAuxilliaryThreshold, out _locFSdfAuxilliaryThreshold); LoadUniform(_nameV4SdfAuxilliaryColor, out _locV4SdfAuxilliaryColor); LoadUniform(_nameX2Texture, out _locX2Texture); LoadUniform(_nameV2TextureOffset, out _locV2TextureOffset); LoadAttribute(_nameV2Postion, out _locV2Position); LoadAttribute(_nameV2Texture, out _locV2Texture); LoadAttribute(_nameV4Color, out _locV4Color); void LoadUniform(string name, out int location) { location = GL.GetUniformLocation(_sp, name); } void LoadAttribute(string name, out int location) { location = GL.GetAttribLocation(_sp, name); } } private readonly int _sp; private const string _nameM4View = "m4View"; private readonly int _locM4View; private const string _nameM4Model = "m4Model"; private readonly int _locM4Model; private const string _nameV2Postion = "v2Position"; private readonly int _locV2Position; private const string _nameV2Texture = "v2Texture"; private readonly int _locV2Texture; private const string _nameV4Color = "v4Color"; private readonly int _locV4Color; private const string _nameIFlags = "iFlags"; private readonly int _locIFlags; private const string _nameFSdfThreshold = "fSdfThreshold"; private readonly int _locFSdfThreshold; private const string _nameFSdfAuxilliaryThreshold = "fSdfAuxilliaryThreshold"; private readonly int _locFSdfAuxilliaryThreshold; private const string _nameV4SdfAuxilliaryColor = "v4SdfAuxilliaryColor"; private readonly int _locV4SdfAuxilliaryColor; private const string _nameX2Texture = "x2Texture"; private readonly int _locX2Texture; private const string _nameV2TextureOffset = "v2TextureOffset"; private readonly int _locV2TextureOffset; [Flags] private enum Flags : int { Texture = 1 << 0, DiscardEnable = 1 << 1, Sdf = 1 << 2, SdfAuxEnable = 1 << 3, } private bool _isDisposed = false; private void Dispose(bool disposing) { if (_isDisposed) return; if (disposing) { GL.DeleteProgram(_sp); } else { throw new Exception("OpenGL resource is leaked. Dispose unreferenced OpenGL objects in the context thread."); } _isDisposed = true; } public void Dispose() => Dispose(true); ~GL30Driver() { Dispose(false); } } }