using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using static Quik.OpenGL.GLEnum; namespace Quik.OpenGL { public unsafe static partial class GL { private delegate int CreateShaderProc(GLEnum type); private delegate void ShaderSourceProc(int shader, int count, byte** strings, int* length); private delegate void CompileShaderProc(int shader); private delegate void GetShaderProc(int shader, GLEnum pname, int* value); private delegate void GetShaderInfoLogProc(int shader, int maxLength, int* length, byte* infoLog); private delegate void DeleteShaderProc(int id); private static CreateShaderProc _createShader; private static ShaderSourceProc _shaderSource; private static CompileShaderProc _compileShader; private static GetShaderProc _getShader; private static GetShaderInfoLogProc _getShaderInfoLog; private static DeleteShaderProc _deleteShader; private static void LoadShader() { _createShader = GetProcAddress("glCreateShader"); _shaderSource = GetProcAddress("glShaderSource"); _compileShader = GetProcAddress("glCompileShader"); _getShader = GetProcAddress("glGetShaderiv"); _getShaderInfoLog = GetProcAddress("glGetShaderInfoLog"); _deleteShader = GetProcAddress("glDeleteShader"); } [MethodImpl(AggressiveInlining)] public static int CreateShader(GLEnum type) => _createShader(type); [MethodImpl(AggressiveInlining)] public static void ShaderSource(int shader, string source) { byte[] sourceUTF8 = Encoding.UTF8.GetBytes(source); int length = sourceUTF8.Length; fixed (byte* ptr = &sourceUTF8[0]) { _shaderSource(shader, 1, &ptr, &length); } } [MethodImpl(AggressiveInlining)] public static void ShaderSource(int shader, string[] sources) { int count = sources.Length; byte*[] pointers = new byte*[count]; int[] lengths = new int[count]; for (int i = 0; i < count; i++) { byte[] decoded = Encoding.UTF8.GetBytes(sources[i]); int length = lengths[i] = decoded.Length; IntPtr memory = Marshal.AllocHGlobal(decoded.Length); Marshal.Copy(decoded, 0, memory, length); pointers[i] = (byte*)memory; } try { fixed (byte** ptr = &pointers[0]) fixed (int * len = &lengths[0]) { _shaderSource(shader, count, ptr, len); } } finally { for (int i = 0; i < count; i++) { Marshal.FreeHGlobal((IntPtr)pointers[i]); } } } [MethodImpl(AggressiveInlining)] public static void CompileShader(int shader) => _compileShader(shader); [MethodImpl(AggressiveInlining)] public static void GetShader(int shader, GLEnum pname, out int value) { value = default; fixed (int *ptr = &value) _getShader(shader, pname, ptr); } [MethodImpl(AggressiveInlining)] public static string GetShaderInfoLog(int shader) { GetShader(shader, GL_INFO_LOG_LENGTH, out int length); byte[] infoLog = new byte[length]; fixed (byte *ptr = infoLog) _getShaderInfoLog(shader, length, &length, ptr); return Encoding.UTF8.GetString(infoLog); } [MethodImpl(AggressiveInlining)] public static void DeleteShader(int shader) => _deleteShader(shader); } }