//+--------------------------------------------------------------------------+
//|                                                                          |
//|                              OpenGL class                                |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                                                                          |
//|                         Author Patrice TERRIER                           |
//|                           copyright (c) 2006                             |
//|                                                                          |
//|                        pterrier@zapsolution.com                          |
//|                                                                          |
//|                          www.zapsolution.com                             |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                  Project started on : 10-17-2006 (MM-DD-YYYY)            |
//|                        Last revised : 10-25-2006 (MM-DD-YYYY)            |
//+--------------------------------------------------------------------------+

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Win32;

namespace OpenGL
{
    class GL
    {
        private const string OPENGL = "opengl32.dll";
        private const string GLU32 = "glu32.dll";
        private const string USER32 = "user32.dll";
        private const string GDI32 = "GDI32.Dll";

        public const int GL_TRIANGLE_FAN = 0x0006;
        public const int GL_DEPTH_TEST = 0x0B71;
        public const int GL_PROJECTION = 0x1701;
        public const int GL_MODELVIEW = 0x1700;
        public const int GL_DEPTH_BUFFER_BIT = 0x100;
        public const int GL_COLOR_BUFFER_BIT = 0x4000;
        public const int GL_LESS = 0x0201;
        public const int GL_TEXTURE_2D = 0x0DE1;
        public const int GL_TRUE = 1;
        public const int GL_COLOR_MATERIAL = 0x0B57;
        public const int GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50;
        public const int GL_NICEST = 0x1102;
        public const int GL_SMOOTH = 0x1D01;
        public const int GL_SRC_ALPHA = 0x0302;
        public const int GL_ONE_MINUS_SRC_ALPHA = 0x0303;
        public const int GL_BLEND = 0x0BE2;
        public const int GL_QUADS = 0x0007;
        public const int GL_TEXTURE_MAG_FILTER = 0x00002800;
        public const int GL_TEXTURE_MIN_FILTER = 0x00002801; 
        public const int GL_LINEAR = 0x00002601;
        public const int GL_RGBA = 0x00001908;
        public const int GL_UNSIGNED_BYTE = 0x00001401;
        public const int GL_LIGHT0 = 0x4000;
        public const int GL_LIGHTING = 0x0B50;
        public const int GL_AMBIENT = 0x1200;
        public const int GL_DIFFUSE = 0x1201;
        public const int GL_POSITION = 0x1203;

        public const int GLU_SMOOTH = 100000;

        public const uint PFD_TYPE_RGBA = 0;
        public const uint PFD_TYPE_COLORINDEX = 1;

        /* layer types */
        public const uint PFD_MAIN_PLANE = 0;
        public const uint PFD_OVERLAY_PLANE = 1;
        public const uint PFD_UNDERLAY_PLANE = 0xff; // (-1)

        /* PIXELFORMATDESCRIPTOR flags */
        public const uint PFD_DOUBLEBUFFER = 0x00000001;
        public const uint PFD_STEREO = 0x00000002;
        public const uint PFD_DRAW_TO_WINDOW = 0x00000004;
        public const uint PFD_DRAW_TO_BITMAP = 0x00000008;
        public const uint PFD_SUPPORT_GDI = 0x00000010;
        public const uint PFD_SUPPORT_OPENGL = 0x00000020;
        public const uint PFD_GENERIC_FORMAT = 0x00000040;
        public const uint PFD_NEED_PALETTE = 0x00000080;
        public const uint PFD_NEED_SYSTEM_PALETTE = 0x00000100;
        public const uint PFD_SWAP_EXCHANGE = 0x00000200;
        public const uint PFD_SWAP_COPY = 0x00000400;
        public const uint PFD_SWAP_LAYER_BUFFERS = 0x00000800;
        public const uint PFD_GENERIC_ACCELERATED = 0x00001000;
        public const uint PFD_SUPPORT_DIRECTDRAW = 0x00002000;

        /* PIXELFORMATDESCRIPTOR flags for use in ChoosePixelFormat only */
        public const uint PFD_DEPTH_DONTCARE = 0x20000000;
        public const uint PFD_DOUBLEBUFFER_DONTCARE = 0x40000000;
        public const uint PFD_STEREO_DONTCARE = 0x80000000;

        [StructLayout(LayoutKind.Sequential)]
        public struct PIXELFORMATDESCRIPTOR
        {
            public ushort nSize;
            public ushort nVersion;
            public uint dwFlags;
            public byte iPixelType;
            public byte cColorBits;
            public byte cRedBits;
            public byte cRedShift;
            public byte cGreenBits;
            public byte cGreenShift;
            public byte cBlueBits;
            public byte cBlueShift;
            public byte cAlphaBits;
            public byte cAlphaShift;
            public byte cAccumBits;
            public byte cAccumRedBits;
            public byte cAccumGreenBits;
            public byte cAccumBlueBits;
            public byte cAccumAlphaBits;
            public byte cDepthBits;
            public byte cStencilBits;
            public byte cAuxBuffers;
            public byte iLayerType;
            public byte bReserved;
            public uint dwLayerMask;
            public uint dwVisibleMask;
            public uint dwDamageMask;
        }

        [DllImport(OPENGL)]
        public static extern void glLightfv(int light, int pname, float[] someParams);
        [DllImport(OPENGL)]
        public static extern void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, byte[] pixels);
        [DllImport(OPENGL)]
        public static extern void glTexParameteri(int target, int pname, int param);
        [DllImport(OPENGL)]
        public static extern void glGenTextures(int n, [Out] int[] textures);
        [DllImport(OPENGL)]
        public static extern int glGetError();
        [DllImport(OPENGL)]
        public static extern void glTranslatef(float x, float y, float z);
        [DllImport(OPENGL)]
        public static extern void glVertex3f(float x, float y, float z);
        [DllImport(OPENGL)]
        public static extern void glRotatef(float angle, float x, float y, float z);
        [DllImport(OPENGL)]
        public static extern void glTexCoord2f(float s, float t);
        [DllImport(OPENGL)]
        public static extern void glClearDepth(double depth);
        [DllImport(OPENGL)]
        public static extern void glBindTexture(int ntarget, int texture);
        [DllImport(OPENGL)]
        public static extern void glClearColor(float red, float green, float blue, float alpha);
        [DllImport(OPENGL)]
        public static extern void glDepthFunc(uint func);
        [DllImport(OPENGL)]
        public static extern void glBlendFunc(uint sfactor, uint dfactor);
        [DllImport(OPENGL)]
        public static extern void glHint(uint ntarget, uint mode);
        [DllImport(OPENGL)]
        public static extern bool wglMakeCurrent(uint glDC, uint glRC);
        [DllImport(OPENGL)]
        public static extern bool wglDeleteContext(uint glRC);
        [DllImport(OPENGL)]
        public static extern uint wglCreateContext(uint glDC);
        [DllImport(OPENGL)]
        public static extern void glClear(uint mask);
        [DllImport(OPENGL)]
        public static extern void glEnable(uint cap);
        [DllImport(OPENGL)]
        public static extern void glDisable(uint cap);
        [DllImport(OPENGL)]
        public static extern void glShadeModel(uint mode);
        [DllImport(OPENGL)]
        public static extern void glLoadIdentity();
        [DllImport(OPENGL)]
        public static extern void glRotated(double angle, double x, double y, double z);
        [DllImport(OPENGL)]
        public static extern void glTranslated(double x, double y, double z);
        [DllImport(OPENGL)]
        public static extern void glBegin(uint mode);
        [DllImport(OPENGL)]
        public static extern void glColor3ub(byte red, byte green, byte blue);
        [DllImport(OPENGL)]
        public static extern void glVertex3d(double x, double y, double z);
        [DllImport(OPENGL)]
        public static extern void glEnd();
        [DllImport(OPENGL)]
        public static extern void glViewport(int x, int y, int width, int height);
        [DllImport(OPENGL)]
        public static extern void glMatrixMode(uint mode);
        [DllImport(OPENGL)]
        public static extern void glFrustum(double left, double right, double bottom, double top, double zNear, double zFar);
        [DllImport(OPENGL)]
        public static extern void glPushMatrix();
        [DllImport(OPENGL)]
        public static extern void glPopMatrix();
        [DllImport(OPENGL)]
        public static extern void glDeleteTextures(int n, ref int textures);

        [DllImport(GLU32)]
        public static extern void gluLookAt(double eyex, double eyey, double eyez, double centerx, double centery, double centerz, double upx, double upy, double upz);
        [DllImport(GLU32)]
        public static extern void gluPerspective(double fovy, double aspect, double zNear, double zFar);
        [DllImport(GLU32)]
        public static extern int gluNewQuadric();
        [DllImport(GLU32)]
        public static extern void gluQuadricNormals(int quadObject, int normals);
        [DllImport(GLU32)]
        public static extern void gluQuadricTexture(int quadObject, int textureCoords);
        [DllImport(GLU32)]
        public static extern void gluSphere(int quadObject, double radius, int slices, int stacks);
        [DllImport(GLU32)]
        public static extern void gluCylinder(int quadObject, double baseradius, double topRadius, double height, int slices, int stacks);
        [DllImport(GLU32)]
        public static extern void gluDeleteQuadric(int quadObject);

        [DllImport(GDI32)]
        public static extern int ChoosePixelFormat(uint hDC, ref PIXELFORMATDESCRIPTOR ppfd);
        [DllImport(GDI32)]
        public static extern uint SetPixelFormat(uint hDC, int iPixelFormat, ref PIXELFORMATDESCRIPTOR ppfd);

        [DllImport(OPENGL)]
        public static extern uint wglSwapBuffers(uint hdc);

        private static double fovy = 1.25;
        public static double Fovy
        {
            get { return fovy; }
            set { fovy = value; }
        }

        //private static IntPtr parent = IntPtr.Zero;
        //public static IntPtr Parent
        //{
        //    get { return parent; }
        //    set { parent = value; }
        //}

        public static void UsePolarView(double radius, double twist, double latitude, double longitude)
        {
            glTranslated(0.0, 0.0, -radius);
            glRotated(-twist, 0.0, 0.0, 1.0);
            glRotated(-latitude, 1.0, 0.0, 0.0);
            glRotated(longitude, 0.0, 0.0, 1.0);
        }

        public static void SetGLPerspective(double fovy, double aspect, double zNear, double zFar)
        {
            double xmin, xmax, ymin, ymax;
            ymax = zNear * Math.Tan(fovy * 0.00872664626);
            ymin = -ymax;
            xmin = ymin * aspect;
            xmax = ymax * aspect;
            glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
        }

        public static bool SetupPixelFormat(uint useDC)
        {
            bool nRet = true;
            PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR();

            pfd.nSize = (ushort) Marshal.SizeOf(pfd);
            pfd.nVersion = 1;
            pfd.dwFlags = (uint)(PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER);
            pfd.dwLayerMask = PFD_MAIN_PLANE;
            pfd.iPixelType = (byte)PFD_TYPE_RGBA;
            pfd.cColorBits = 24; //32
            pfd.cDepthBits = 16; //16

            int iPixelformat = ChoosePixelFormat(useDC, ref pfd);
            if (iPixelformat != 0)
            {
                if (SetPixelFormat(useDC, iPixelformat, ref pfd) == 0) nRet = false;
            }
            else
            {
                nRet = false;
            }
            return nRet;
        }

    } // END OpenGL interface
}
