using System.Runtime.CompilerServices;

namespace Quik.OpenGL
{
    public unsafe static partial class GL
    {
        private delegate void Uniform1fProc(int location, float x);
        private delegate void Uniform2fProc(int location, float x, float y);
        private delegate void Uniform3fProc(int location, float x, float y, float z);
        private delegate void Uniform4fProc(int location, float x, float y, float z, float w);
        private delegate void Uniform1iProc(int location, int x);
        private delegate void Uniform2iProc(int location, int x, int y);
        private delegate void Uniform3iProc(int location, int x, int y, int z);
        private delegate void Uniform4iProc(int location, int x, int y, int z, int w);
        private delegate void UniformNfvProc(int location, int count, float* value);
        private delegate void UniformNivProc(int location, int count, int* value);
        private delegate void UniformMatrixNxNfvProc(int location, int count, bool transpose, float *value);

        private static Uniform1fProc _uniform1f;
        private static Uniform2fProc _uniform2f;
        private static Uniform3fProc _uniform3f;
        private static Uniform4fProc _uniform4f;
        private static Uniform1iProc _uniform1i;
        private static Uniform2iProc _uniform2i;
        private static Uniform3iProc _uniform3i;
        private static Uniform4iProc _uniform4i;
        private static UniformNfvProc _uniform1fv;
        private static UniformNfvProc _uniform2fv;
        private static UniformNfvProc _uniform3fv;
        private static UniformNfvProc _uniform4fv;
        private static UniformNivProc _uniform1iv;
        private static UniformNivProc _uniform2iv;
        private static UniformNivProc _uniform3iv;
        private static UniformNivProc _uniform4iv;
        private static UniformMatrixNxNfvProc _uniformMatrix2fv;
        private static UniformMatrixNxNfvProc _uniformMatrix3fv;
        private static UniformMatrixNxNfvProc _uniformMatrix4fv;

        public static void LoadUniform()
        {
            _uniform1f = GetProcAddress<Uniform1fProc>("glUniform1f");
            _uniform2f = GetProcAddress<Uniform2fProc>("glUniform2f");
            _uniform3f = GetProcAddress<Uniform3fProc>("glUniform3f");
            _uniform4f = GetProcAddress<Uniform4fProc>("glUniform4f");
            _uniform1i = GetProcAddress<Uniform1iProc>("glUniform1i");
            _uniform2i = GetProcAddress<Uniform2iProc>("glUniform2i");
            _uniform3i = GetProcAddress<Uniform3iProc>("glUniform3i");
            _uniform4i = GetProcAddress<Uniform4iProc>("glUniform4i");
            _uniform1fv = GetProcAddress<UniformNfvProc>("glUniform1fv");
            _uniform2fv = GetProcAddress<UniformNfvProc>("glUniform2fv");
            _uniform3fv = GetProcAddress<UniformNfvProc>("glUniform3fv");
            _uniform4fv = GetProcAddress<UniformNfvProc>("glUniform4fv");
            _uniform1iv = GetProcAddress<UniformNivProc>("glUniform1iv");
            _uniform2iv = GetProcAddress<UniformNivProc>("glUniform2iv");
            _uniform3iv = GetProcAddress<UniformNivProc>("glUniform3iv");
            _uniform4iv = GetProcAddress<UniformNivProc>("glUniform4iv");
            _uniformMatrix2fv = GetProcAddress<UniformMatrixNxNfvProc>("glUniformMatrix2fv");
            _uniformMatrix3fv = GetProcAddress<UniformMatrixNxNfvProc>("glUniformMatrix3fv");
            _uniformMatrix4fv = GetProcAddress<UniformMatrixNxNfvProc>("glUniformMatrix4fv");
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform1(int location, float x)
        {
            _uniform1f(location, x);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform2(int location, float x, float y)
        {
            _uniform2f(location, x, y);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform3(int location, float x, float y, float z)
        {
            _uniform3f(location, x, y, z);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform4(int location, float x, float y, float z, float w)
        {
            _uniform4f(location, x, y, z, w);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform1(int location, int x)
        {
            _uniform1i(location, x);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform2(int location, int x, int y)
        {
            _uniform2i(location, x, y);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform3(int location, int x, int y, int z)
        {
            _uniform3i(location, x, y, z);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform4(int location, int x, int y, int z, int w)
        {
            _uniform4i(location, x, y, z, w);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform1(int location, int count, ref float first)
        {
            fixed(float *ptr = &first)
                _uniform1fv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform2(int location, int count, ref float first)
        {
            fixed(float *ptr = &first)
                _uniform2fv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform3(int location, int count, ref float first)
        {
            fixed(float *ptr = &first)
                _uniform3fv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform4(int location, int count, ref float first)
        {
            fixed(float *ptr = &first)
                _uniform4fv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform1(int location, int count, ref int first)
        {
            fixed(int *ptr = &first)
                _uniform1iv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform2(int location, int count, ref int first)
        {
            fixed(int *ptr = &first)
                _uniform2iv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform3(int location, int count, ref int first)
        {
            fixed(int *ptr = &first)
                _uniform3iv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void Uniform4(int location, int count, ref int first)
        {
            fixed(int *ptr = &first)
                _uniform4iv(location, count, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix2(int location, bool transpose, ref float m11)
        {
            fixed (float* ptr = &m11)
                _uniformMatrix2fv(location, 1, transpose, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix3(int location, bool transpose, ref float m11)
        {
            fixed (float* ptr = &m11)
                _uniformMatrix3fv(location, 1, transpose, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix4(int location, bool transpose, ref float m11)
        {
            fixed (float* ptr = &m11)
                _uniformMatrix4fv(location, 1, transpose, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix2(int location, int count, bool transpose, ref float m11)
        {
            fixed (float* ptr = &m11)
                _uniformMatrix2fv(location, count, transpose, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix3(int location, int count, bool transpose, ref float m11)
        {
            fixed (float* ptr = &m11)
                _uniformMatrix3fv(location, count, transpose, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix4(int location, int count, bool transpose, ref float m11)
        {
            fixed (float* ptr = &m11)
                _uniformMatrix4fv(location, count, transpose, ptr);
        }

    [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix4(int location, bool transpose, in QMat4 m4)
        {
            fixed (float* ptr = &m4.M11)
                _uniformMatrix4fv(location, 1, transpose, ptr);
        }

        [MethodImpl(AggressiveInlining)]
        public static void UniformMatrix4(int location, int count, bool transpose, ref QMat4 m4)
        {
            fixed (float* ptr = &m4.M11)
                _uniformMatrix4fv(location, count, transpose, ptr);
        }
    }
}