/*

// wrapper for {OpenGL} control in C# -- based on CSGL12 library by Colin P. Fahey.
// For using CSGL12 with AL4/C#, we suggest not to bring 2 dlls together with a
// project but to compile sources together with a project. To do so:
// 1. place CSGL12Control.cs, GL.cs, PrecisionTime.cs source files into a single
//    directory on a disk;
// 2. Add an environment variable CSGL12 setting it to a path to that directory;
//------------------------------------------------------------------------------
// (C) by Vladimir Kladov, 2017


CLASS {AL4_OpenGL|_csharp}, NATIVE, UNTESTED :

IMPORT: {OpenGL} .

NATIVE: "using CSGL12;" .

*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

using System.Runtime.InteropServices;

using AL4;
using AL4_project;
using CSGL12;

public class AL4_OpenGL 
{
    
    /*
    
    FUN Create_opengl_control({OpenGL} GL|_control) ==> INT :
        //------------------------------------- 'dummy operation to use {Picture}'
        //{layout_image} layout_dummy = 'STRETCHED'
        ---------------------------------------- 'redirect to GL control create'
        INT f|orm_handle = GL_control.Form_.Handle
        RESULT = do_Create_opengl_control(f, GL) .
    FUN do_Create_opengl_control(
    INT Form|_handle, {OpenGL} GL|_control) ==> INT, NATIVE : @
    "   RESULT = AL4_OpenGL.Do_Create_opengl_control((int)X_Form, X_GL);" .
    */
    
    public static int Do_Create_opengl_control(int H, Ref_obj X_G)
    {
        AL4Column P = AL4Form.Get_parent_for_new_control(H);
        CSGL12Control G = new CSGL12Control();
        
        G.BackColor = SystemColors.Control;
        P.Controls.Add(G);
        P.Child_controls.Add(G);
        G.Parent = P;
        
        int Result = AL4Form.AllocDescriptor(G);
        G.Tag = X_G;
        AL4Form.Adjust_control_location(P);
        AL4Form.Set_control_events(P, G);
        
        AL4_OpenGL Handler = new AL4_OpenGL(G);
        G.OpenGLStarted += new CSGL12Control.DelegateOpenGLStarted( Handler.OpenGLStarted );
        G.Paint += new PaintEventHandler( Handler.Paint );
        
        return Result;
    }
    
    //----------------------------
    // use class AL4_OpenGL instance as a handler object for event
    // "Open GL started". So, we need a constructor too:
    CSGL12Control GL_control;
    
    public AL4_OpenGL(CSGL12Control G)
    {
        GL_control = G;
    }
    
    public void OpenGLStarted( CSGL12Control G )
    {
        G.Invalidate();

        gl_object = G.GetGL();
        if (gl == null) { return; }

        // To prevent "tearing" (irregular streaks) due to swapping buffers at
        // arbitrary times relative to the vsync times, we indicate that we wish
        // to wait for vsync before swapping buffers.
        // This request applies when the display driver control panel -- in the
        // OpenGL settings area -- is set to let the application decide whether or
        // not to wait for vsync.  Otherwise, the driver control panel overrides
        // any request made here.

        if (gl.bwglSwapIntervalEXT)
        {
            // ALLOW TEARING
            gl.wglSwapIntervalEXT(0);
        }
        
    }
    
    // all these "tribe dances" just to prevent crashes if gl is called BEFORE
    // any paint on {OpenGL} component.
    public static GL gl_object = null;
    static CSGL12Control fake_control = null;
    
    public static GL gl 
    {
        get
        {
            if (gl_object == null)
            {
                fake_control = new CSGL12Control();
                AL4_OpenGL Handler = new AL4_OpenGL(fake_control);
                fake_control.OpenGLStarted += 
                new CSGL12Control.DelegateOpenGLStarted( Handler.OpenGLStarted );
                gl_object = fake_control.GetGL();
                IntPtr DC = (IntPtr)0;
                IntPtr RC = (IntPtr)0;
                gl_object.InitializeOpenGL(fake_control.Handle, ref DC, ref RC);
            }
            return gl_object;
        }
    }
        
    public void Paint(object sender, PaintEventArgs e)
    {
        if (sender == null) return;
        if (!(sender is CSGL12Control)) return;
        CSGL12Control G = (sender as CSGL12Control);
        gl_object = G.GetGL();

        // Set the viewport 
        int clientWidth = G.ClientRectangle.Width;
        int clientHeight = G.ClientRectangle.Height;
        if (clientWidth <= 0) clientWidth = 1;
        if (clientHeight <= 0) clientHeight = 1;
        gl_object.glViewport(0, 0, clientWidth, clientHeight);

        // pass control to an AL4 code (placed in OVERRIDE FUN paint of a parent form)
        C_OpenGL CGL = (C_OpenGL)((Ref_obj)G.Tag).Obj;
        if (G.Parent != null && G.Parent.Parent is AL4Form)
        {
            AL4Form AForm = (AL4Form)G.Parent.Parent;
            C_Form Form = (C_Form)AForm.AL4Object.Obj;
            
            //{
            //    AL4_object.Object_assign_hard(ref Form.F_sender, ((Ref_obj)G.Tag).Obj);
            //}
            
            Form.Do.M_operation_started(22, (Ref_obj)G.Tag);
            try {
            Form.Do.M_paint();
            } catch(Stop) {}
            Form.Do.M_operation_ended(22);
            
            //AL4_object.Object_assign_hard(ref Form.F_sender, C_Control.NoneObj_C_Control);
        }

        // FINALLY, flush all the current rendering and flip the back buffer to the front.
        gl_object.wglSwapBuffers(G.GetHDC());
        
        //gl = null; // do not nullify gl variable, so it is possible to use it 
                     // "after and out of" paint function without a crash
                     // though this can lead to undesired behaviour.
    }
    
    public static List<IntPtr> All_quadrics = new List<IntPtr>();
    
    public static int do_gluNewQuadric()
    {
        if (All_quadrics.Count == 0)
            All_quadrics.Add((IntPtr)(-1));
        int Result = All_quadrics.IndexOf((IntPtr)0);
        if (Result < 0)
        {
            Result = All_quadrics.Count;
            All_quadrics.Add((IntPtr)0);
        }
        All_quadrics[Result] = gl.gluNewQuadric();
        if (All_quadrics[Result] == (IntPtr)0) Result = 0;
        return Result;
    }
    
    public static void do_gluDeleteQuadric(int quadric)
    {
        if (quadric < 1 || quadric >= All_quadrics.Count) return;
        if (All_quadrics[quadric] == (IntPtr)0) return;
        try {
            gl.gluDeleteQuadric(All_quadrics[quadric]);
        }
        catch (Exception e) { }
        All_quadrics[quadric] = (IntPtr)0;
    }
    
    public static IntPtr quadric(int index)
    {
        if (index < 0 || index >= All_quadrics.Count) return (IntPtr)0;
        return All_quadrics[index];
    }
    
    private delegate IntPtr DglGetString_I( int name );
    private static DglGetString_I mDglGetString_I;
    public static bool bglGetString;
    
    public static String GLGetString(int name)
    {
        if (mDglGetString_I == null)
        {
            mDglGetString_I = GetDelegate( "glGetString", 
                typeof( DglGetString_I ), ref bglGetString ) as DglGetString_I;
        }

        IntPtr Rslt_I = mDglGetString_I != null ? mDglGetString_I( name ) : (IntPtr)0;
        String Result = Rslt_I != (IntPtr)0 ? (Marshal.PtrToStringAnsi(Rslt_I))
                                            : "null" ;
        return Result;
    }
    
    
    /*
    FUN Invalidate_open_gl_control(INT H|andle_control), NATIVE :
       @"    CSGL12Control G = (CSGL12Control)AL4Form.All_descriptors["
       "		(int)X_H];"
        "    G.Invalidate();" .
        
    FUN Update_open_gl_control(INT H|andle_control), NATIVE :
       @"    CSGL12Control G = (CSGL12Control)AL4Form.All_descriptors["
       "		(int)X_H];"
        "    G.Invalidate();" 
        "    G.Update();"
        .

        
    FUN Format_pixels_from_internal_format_bitmap( 
        INT I|nternal_format ) ==> INT
        :
        ----------------------------------------- 'for C++/wxWidgets'
        CASE I ?
        [GL_RGB, 3]: RESULT = GL_BGR
        ELSE RESULT = GL_BGRA ; .

        
    FUN Type_pixels_from_internal_format_bitmap( INT I|nternal_format ) ==> INT
        :
        ----------------------------------------- 'for C++/wxWidgets'
        CASE I ?
        [GL_RGB, 3]: RESULT = GL_UNSIGNED_BYTE
        ELSE RESULT = GL_UNSIGNED_BYTE ; .
        
    
    CONST STR : NATIVE_import_OpenGL = ""
    
                NATIVE_glGetError = @
                "    RESULT = AL4_OpenGL.gl.glGetError();"
    
                NATIVE_gluErrorString = @
                "    RESULT = AL4_OpenGL.gl.gluErrorString((int)X_Code);"
    
                NATIVE_glGetString = @
                "       RESULT = AL4_OpenGL.GLGetString((int)X_Name);"
    
                NATIVE_glViewport = @
                "    AL4_OpenGL.gl.glViewport("
                "		(int)X_X, (int)X_Y, (int)X_Width, (int)X_Height);"
    
                NATIVE_glClearColor = @
                "    AL4_OpenGL.gl.glClearColor("
                "    (float)X_R, (float)X_G, (float)X_B, (float)X_A);"
                
                NATIVE_glClearDepth = @
                "    AL4_OpenGL.gl.glClearDepth(X_Depth);"
                
                NATIVE_glClearStencil = @
                "    AL4_OpenGL.gl.glClearStencil((int)X_S);"
                
                NATIVE_glAccum = @
                "    AL4_OpenGL.gl.glAccum((int)X_Op, (float)X_Value);"
                
                NATIVE_glClearAccum = @
                "    AL4_OpenGL.gl.glClearAccum("
                "    (float)X_R, (float)X_G, (float)X_B, (float)X_A);"
                
                NATIVE_glClear = @
                "    AL4_OpenGL.gl.glClear((int)X_B);"
                
                NATIVE_glEnable = @
                "    AL4_OpenGL.gl.glEnable((int)X_What);"
                
                NATIVE_glDisable = @
                "    AL4_OpenGL.gl.glDisable((int)X_What);"
                
                NATIVE_glIsEnabled = @
                "    RESULT = AL4_OpenGL.gl.glIsEnabled((int)X_What) != 0;"
                
                NATIVE_glGetBooleanv = @
                "    byte[] p = new byte[1];"
                "    AL4_OpenGL.gl.glGetBooleanv((int)X_What, p);"
                "    X_Params.Clear();"
                "    X_Params.Add(p[0] != 0);"
                
                NATIVE_glGetIntegerv = @
                "    int[] p = new int[X_size];"
                "    AL4_OpenGL.gl.glGetIntegerv((int)X_What, p);"
                "    X_Param.Clear();"
                "    for (int i = 0; i < p.Length; i++)"
                "        X_Param.Add(p[i]);"
                
                NATIVE_glGetDoublev = @
                "    double[] p = new double[X_size];"
                "    AL4_OpenGL.gl.glGetDoublev((int)X_What, p);"
                "    X_Param.Clear();"
                "    for (int i = 0; i < p.Length; i++)"
                "        X_Param.Add(p[i]);"
                
                NATIVE_glColorMask = @
                "    AL4_OpenGL.gl.glColorMask(X_Red ? (byte)1 : (byte)0,"
                "       X_Green ? (byte)1 : (byte)0,"
                "       X_Blue ? (byte)1 : (byte)0,"
                "       X_Alpha ? (byte)1 : (byte)0);"
                
                NATIVE_glCullFace = @
                "    AL4_OpenGL.gl.glCullFace((int)X_Side);"
                
                NATIVE_glDepthFunc = @
                "    AL4_OpenGL.gl.glDepthFunc((int)X_Func);"
                
                NATIVE_glDepthMask = @
                "    AL4_OpenGL.gl.glDepthMask(X_Flag ? (byte)1 : (byte)0);"
                
                NATIVE_glDepthRange = @
                "    AL4_OpenGL.gl.glDepthRange((float)X_Near, (float)X_Far);"
                
                NATIVE_glLineWidth = @
                "    AL4_OpenGL.gl.glLineWidth((float)X_Width);"
                
                NATIVE_glLineStipple = @
                "    AL4_OpenGL.gl.glLineStipple("
                "		(int)X_Factor, (short)X_Pattern);"
                
                NATIVE_glPointSize = @
                "    AL4_OpenGL.gl.glPointSize((float)X_Size);"
                
                NATIVE_glPolygonMode = @
                "    AL4_OpenGL.gl.glPolygonMode((int)X_Face, (int)X_Mode);"
                
                NATIVE_glPolygonOffset = @
                "    AL4_OpenGL.gl.glPolygonOffset((float)X_Factor,"
                "       (float)X_Units);"
                
                NATIVE_glHint = @
                "    AL4_OpenGL.gl.glHint((int)X_Target, (int)X_Mode);"
                
                NATIVE_glFrontFace = @
                "    AL4_OpenGL.gl.glFrontFace((int)X_Orient);"
                
                NATIVE_glMatrixMode = @
                "    AL4_OpenGL.gl.glMatrixMode((int)X_Mode);"
                
                NATIVE_glLoadIdentity = @
                "    AL4_OpenGL.gl.glLoadIdentity();"
                
                NATIVE_glPushMatrix = @
                "    AL4_OpenGL.gl.glPushMatrix();"
                
                NATIVE_glPopMatrix = @
                "    AL4_OpenGL.gl.glPopMatrix();"
                
                NATIVE_glMultMatrixd = @
                "    double[] p = new double[16];"
                "    for (int i = 0; i < X_Matrix.Count; i++)"
                "        p[i] = X_Matrix[i];"
                "    AL4_OpenGL.gl.glMultMatrixd(p);"
                
                NATIVE_glTranslated = @
                "    AL4_OpenGL.gl.glTranslated(X_X, X_Y, X_Z);"
                
                NATIVE_glTranslatef = @
                "    AL4_OpenGL.gl.glTranslatef((float)X_X, (float)X_Y,"
                "       (float)X_Z);"
                
                NATIVE_glRotated = @
                "    AL4_OpenGL.gl.glRotated(X_A, X_X, X_Y, X_Z);"
                
                NATIVE_glRotatef = @
                "    AL4_OpenGL.gl.glRotatef((float)X_A, (float)X_X,"
                "       (float)X_Y, (float)X_Z);"
                
                NATIVE_glScaled = @
                "    AL4_OpenGL.gl.glScaled(X_X, X_Y, X_Z);"
                
                NATIVE_glScalef = @
                "    AL4_OpenGL.gl.glScalef((float)X_X, (float)X_Y,"
                "       (float)X_Z);"
                
                NATIVE_gluPerspective = @
                "    AL4_OpenGL.gl.gluPerspective(X_VerticalFOV, X_Aspect, "
                "       X_Near, X_Far);"
                
                NATIVE_gluOrtho2D = @
                "    AL4_OpenGL.gl.gluOrtho2D(X_Left, X_Right, X_Top, "
                "       X_Bottom);"
                
                NATIVE_glOrtho = @
                "    AL4_OpenGL.gl.glOrtho(X_Left, X_Right, "
                "       X_Bottom, X_Top, X_Near, X_Far);"
                
                NATIVE_glFrustum = @
                "    AL4_OpenGL.gl.glFrustum(X_Left, X_Right, "
                "       X_Bottom, X_Top, X_Near, X_Far);"
                
                NATIVE_gluProject = @
                "    double[] m = new double[16];"
                "    for (int i = 0; i < 16 && i < X_Model.Count; i++)"
                "        m[i] = X_Model[i];"
                "    double[] p = new double[16];"
                "    for (int i = 0; i < 16 && i < X_Project.Count; i++)"
                "        p[i] = X_Project[i];"
                "    int[] v = new int[4];"
                "    for (int i = 0; i < 4 && i < X_Viewport.Count; i++)"
                "        v[i] = (int)X_Viewport[i];"
                "    double[] r = new double[3];"
                "    AL4_OpenGL.gl.gluProject(X_X_obj, X_Y_obj, X_Z_obj,"
                "       m, p, v, ref r[0], ref r[1], ref r[2]);"
                "    for (int i =0; i < 3 && i < X_XYZ_win.Count; i++)"
                "       X_XYZ_win[i] = r[i];"
                
                NATIVE_gluUnProject = @
                "    double[] m = new double[16];"
                "    for (int i = 0; i < 16 && i < X_Model.Count; i++)"
                "        m[i] = X_Model[i];"
                "    double[] p = new double[16];"
                "    for (int i = 0; i < 16 && i < X_Project.Count; i++)"
                "        p[i] = X_Project[i];"
                "    int[] v = new int[4];"
                "    for (int i = 0; i < 4 && i < X_Viewport.Count; i++)"
                "        v[i] = (int)X_Viewport[i];"
                "    double[] r = new double[3];"
                "    AL4_OpenGL.gl.gluUnProject(X_X_win, X_Y_win, X_Z_win,"
                "       m, p, v, ref r[0], ref r[1], ref r[2]);"
                "    for (int i = 0; i < 3 && i < X_XYZ_obj.Count; i++)"
                "       X_XYZ_obj[i] = r[i];"

                
                NATIVE_glClipPlane = @
                "    double[] p = new double[4];"
                "    for (int i = 0; i < 4 && i < X_Equation.Count; i++)"
                "        p[i] = X_Equation[i];"
                "    AL4_OpenGL.gl.glClipPlane((int)X_Plane, p);"
                
                NATIVE_glPushAttrib = @
                "    AL4_OpenGL.gl.glPushAttrib((int)X_Mask);"
                
                NATIVE_glPopAttrib = @
                "    AL4_OpenGL.gl.glPopAttrib();"
                
                NATIVE_glPushClientAttrib = @
                "    AL4_OpenGL.gl.glPushClientAttrib((int)X_Mask);"
                
                NATIVE_glPopClientAttrib = @
                "    AL4_OpenGL.gl.glPopClientAttrib();"
                
                
                
                NATIVE_glBegin = @
                "    AL4_OpenGL.gl.glBegin((int)X_Mode);"
                
                NATIVE_glEnd = @
                "    AL4_OpenGL.gl.glEnd();"
                
        NATIVE_glListBase = @
        "    AL4_OpenGL.gl.glListBase((int)X_Base);"
        
        NATIVE_glGenLists = @
        "    RESULT = AL4_OpenGL.gl.glGenLists((int)X_Range);"
        
        NATIVE_glIsList = @
        "    RESULT = AL4_OpenGL.gl.glIsList((int)X_List) != 0;"
        
        NATIVE_glNewList = @
        "    AL4_OpenGL.gl.glNewList((int)X_List, (int)X_Mode);"
        
        NATIVE_glEndList = @
        "    AL4_OpenGL.gl.glEndList();"
        
        NATIVE_glCallList = @
        "    AL4_OpenGL.gl.glCallList((int)X_List);"
        
        NATIVE_glCallLists = @
        "    if (X_N <= 0) X_N = X_Lists.Count;"
        "    if (X_N > X_Lists.Count) X_N = X_Lists.Count;"
        "    if (X_N == 0) return;"
        "    int[] lists = new int[X_N];"
        "    for (int i = 0; i < X_N; i++)"
        "       lists[i] = (int)X_Lists[i];"
        "    AL4_OpenGL.gl.glCallLists((int)X_N, (int)X_Type, lists);"
        
        NATIVE_glDeleteLists = @
        "    AL4_OpenGL.gl.glDeleteLists((int)X_List, (int)X_Range);"
        
                NATIVE_glVertex2d = @
                "    AL4_OpenGL.gl.glVertex2d(X_X, X_Y);"
                
                NATIVE_glVertex2f = @
                "    AL4_OpenGL.gl.glVertex2f((float)X_X, (float)X_Y);"
                
                NATIVE_glVertex3d = @
                "    AL4_OpenGL.gl.glVertex3d(X_X, X_Y, X_Z);"
                
                NATIVE_glVertex3f = @
                "    AL4_OpenGL.gl.glVertex3f((float)X_X, (float)X_Y,"
                "       (float)X_Z);"
                
                NATIVE_glVertex4d = @
                "    AL4_OpenGL.gl.glVertex4d(X_X, X_Y, X_Z, X_W);"
                
                NATIVE_glVertex4f = @
                "    AL4_OpenGL.gl.glVertex4f((float)X_X, (float)X_Y,"
                "       (float)X_Z, (float)X_W);"
                
                NATIVE_glTexCoord1d = @
                "    AL4_OpenGL.gl.glTexCoord1d(X_S);"
                
                NATIVE_glTexCoord1f = @
                "    AL4_OpenGL.gl.glTexCoord1f((float)X_S);"
                
                NATIVE_glTexCoord2d = @
                "    AL4_OpenGL.gl.glTexCoord2d(X_S, X_T);"
                
                NATIVE_glTexCoord2f = @
                "    AL4_OpenGL.gl.glTexCoord2f((float)X_S, (float)X_T);"
                
                NATIVE_glTexCoord3d = @
                "    AL4_OpenGL.gl.glTexCoord3d(X_S, X_T, X_R);"
                
                NATIVE_glTexCoord3f = @
                "    AL4_OpenGL.gl.glTexCoord3f((float)X_S, (float)X_T,"
                "       (float)X_R);"
                
                NATIVE_glTexCoord4d = @
                "    AL4_OpenGL.gl.glTexCoord4d(X_S, X_T, X_R, X_Q);"
                
                NATIVE_glTexCoord4f = @
                "    AL4_OpenGL.gl.glTexCoord4f((float)X_S, (float)X_T,"
                "       (float)X_R, (float)X_Q);"
                
                NATIVE_glNormal3d = @
                "    AL4_OpenGL.gl.glNormal3d(X_X, X_Y, X_Z);"
                
                NATIVE_glNormal3f = @
                "    AL4_OpenGL.gl.glNormal3f((float)X_X, (float)X_Y,"
                "       (float)X_Z);"
                
                NATIVE_glColor3d = @
                "    AL4_OpenGL.gl.glColor3d(X_Red, X_Green, X_Blue);"
                
                NATIVE_glColor3f = @
                "    AL4_OpenGL.gl.glColor3f((float)X_Red, (float)X_Green,"
                "       (float)X_Blue);"
                
                NATIVE_glColor4d = @
                "    AL4_OpenGL.gl.glColor4d(X_Red, X_Green, X_Blue, X_Alpha);"
                
                NATIVE_glColor4f = @
                "    AL4_OpenGL.gl.glColor4f((float)X_Red, (float)X_Green,"
                "       (float)X_Blue, (float)X_Alpha);"
                
        NATIVE_glGenTextures = @
        "    if (X_N <= 0) return;"
        "    int[] t = new int[X_N];"
        "    AL4_OpenGL.gl.glGenTextures( (int)X_N, t );"
        "    for (int i = 0; i < X_N; i++)"
        "        X_Textures.Add(t[i]);"
        
        NATIVE_glIsTexture = @
        "    RESULT = AL4_OpenGL.gl.glIsTexture((int)X_Texture) != 0;"
        
        NATIVE_glDeleteTextures = @
        "    if (X_N <= 0) X_N = X_Textures.Count;"
        "    if (X_N >= X_Textures.Count) X_N = X_Textures.Count - 1;"
        "    if (X_N <= 0) return;"
        "    int[] t = new int[X_N];"
        "    for (int i = 0; i < X_N; i++)"
        "        t[i] = (int)X_Textures[i];"
        "    AL4_OpenGL.gl.glDeleteTextures( (int)X_N, t );"
        
        NATIVE_glBindTexture = @
        "    AL4_OpenGL.gl.glBindTexture((int)X_Target, (int)X_Texture);"
        
        NATIVE_glTexImage1D = @
        "    try {"
        "    AL4_OpenGL.gl.glTexImage1D((int)X_Target, (int)X_Level, "
        "		(int)X_Internal_format, (int)X_Width, (int)X_Border, "
        "		(int)X_Format, (int)X_Type, X_Data.ToBytesArray());"
        "    }"
        "    catch (Exception e) {"
        "          AL4_system.Any_exception(e);"
        "    }"
        
        NATIVE_glTexSubImage1D = @
        "    try {"
        "    AL4_OpenGL.gl.glTexSubImage1D((int)X_Target, (int)X_Level, "
        "		(int)X_X_offset, (int)X_Width, (int)X_Format, (int)X_Type, "
        "		X_Data.ToBytesArray());"
        "    }"
        "    catch (Exception e) {"
        "          AL4_system.Any_exception(e);"
        "    }"
        
        NATIVE_glTexImage2D = @
        "    try {"
        "    AL4_OpenGL.gl.glTexImage2D((int)X_Target, (int)X_Level, "
        "		(int)X_Internal_format,"
        "       (int)X_Width, (int)X_Height, (int)X_Border, "
        "		(int)X_Format, (int)X_Type,"
        "       X_Data.ToBytesArray());"
        "    }"
        "    catch (Exception e) {"
        "          AL4_system.Any_exception(e);"
        "    }"
        
        NATIVE_glTexSubImage2D = @
        "    try {"
        "    AL4_OpenGL.gl.glTexSubImage2D((int)X_Target, (int)X_Level, "
        "		(int)X_X_offset, (int)X_Y_offset, (int)X_Width, (int)X_Height, "
        "		(int)X_Format, (int)X_Type,"
        "       X_Data.ToBytesArray());"
        "    }"
        "    catch (Exception e) {"
        "          AL4_system.Any_exception(e);"
        "    }"
        
        //NATIVE_glTexImage3D = @
        //"    AL4_OpenGL.gl.glTexImage3D(X_Target, X_Level, X_Internal_format,"
        //"       X_Width, X_Height, X_Depth, X_Border, X_Format, X_Type,"
        //"       ((FixAByte_OnArray)X_Data.BaseList).BaseArray);"
        
        //NATIVE_glTexSubImage3D = @
        //"    AL4_OpenGL.gl.glTexSubImage3D(X_Target, X_Level, X_X_offset,"
        //"       X_Y_offset, X_Z_offset, X_Width, X_Height, X_Depth, X_Format,"
        //"       X_Type,"
        //"       ((FixAByte_OnArray)X_Data.BaseList).BaseArray);"
        
        NATIVE_gluBuild1DMipmaps = @
        "    try {"
        "    AL4_OpenGL.gl.gluBuild1DMipmaps((int)X_Target, (int)X_Components, "
        "		(int)X_Width, (int)X_Format, (int)X_Type, "
        "		X_Data.ToBytesArray());"
        "    }"
        "    catch (Exception e) {"
        "          AL4_system.Any_exception(e);"
        "    }"
        
        NATIVE_gluBuild2DMipmaps = @
        "    try {"
        "    AL4_OpenGL.gl.gluBuild2DMipmaps((int)X_Target, (int)X_Components, "
        "		(int)X_Width, (int)X_Height, (int)X_Format, (int)X_Type, "
        "		X_Data.ToBytesArray());"
        "    }"
        "    catch (Exception e) {"
        "          AL4_system.Any_exception(e);"
        "    }"
        
        NATIVE_glTexParameteri = @
        "    AL4_OpenGL.gl.glTexParameteri("
        "			(int)X_Target, (int)X_Pname, (int)X_Param);"
        
        NATIVE_glTexParameterf = @
        "    AL4_OpenGL.gl.glTexParameterf("
        "		(int)X_Target, (int)X_Pname, (float)X_Param);"
        
        NATIVE_glTexParameterfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count) n = X_Param.Count;"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param[i];"
        "    AL4_OpenGL.gl.glTexParameterfv((int)X_Target, (int)X_Pname, p);"
        
        NATIVE_glTexEnvi = @
        "    AL4_OpenGL.gl.glTexEnvi("
        "			(int)X_Target, (int)X_Pname, (int)X_Param);"
        
        NATIVE_glTexEnvf = @
        "    AL4_OpenGL.gl.glTexEnvf("
        "			(int)X_Target, (int)X_Pname, (float)X_Param);"
        
        NATIVE_glBlendFunc = @
        "    AL4_OpenGL.gl.glBlendFunc((int)X_Sfactor, (int)X_Dfactor);"
        
        //NATIVE_glBlendFuncSeparate = @
        //"    AL4_OpenGL.gl.glBlendFuncSeparate(X_SrcRGB, X_DstRGB, X_SrcAlpha,"
        //"       X_DstAlpha);"
        
        //NATIVE_glBlendColor = @
        //"    AL4_OpenGL.gl.glBlendColor((float)X_Red, (float)X_Green,"
        //"       (float)X_Blue, (float)X_Alpha);"
        
        //NATIVE_glBlendEquation = @
        //"    AL4_OpenGL.gl.glBlendEquation(X_Mode);"
        
        //NATIVE_glBlendEquationSeparate = @
        //"    AL4_OpenGL.gl.glBlendEquationSeparate(X_ModeRGB, X_ModeAlpha);"
        
        NATIVE_glAlphaFunc = @
        "    AL4_OpenGL.gl.glAlphaFunc((int)X_Func, (float)X_Ref);"
        
        NATIVE_glStencilFunc = @
        "    AL4_OpenGL.gl.glStencilFunc((int)X_Func, (int)X_Ref, (int)X_Mask);"
        
        NATIVE_glStencilOp = @
        "    AL4_OpenGL.gl.glStencilOp("
        "		(int)X_Ffail, (int)X_Dpfail, (int)X_Dppass);"
        
        NATIVE_glStencilMask = @
        "    AL4_OpenGL.gl.glStencilMask((int)X_Mask);"
        
        NATIVE_glLightf = @
        "AL4_OpenGL.gl.glLightf((int)X_Light, (int)X_Pname, (float)X_Param);"
        
        NATIVE_glLightfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count) n = X_Param.Count;"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param[i];"
        "    AL4_OpenGL.gl.glLightfv((int)X_Light, (int)X_Pname, p);"
        
        NATIVE_glLightModeli = @
        "    AL4_OpenGL.gl.glLightModeli((int)X_Pname, (int)X_Param);"
        
        NATIVE_glLightModelfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count) n = X_Param.Count;"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param[i];"
        "    AL4_OpenGL.gl.glLightModelfv((int)X_Pname, p);"
        
        NATIVE_glMaterialf = @
        "    AL4_OpenGL.gl.glMaterialf("
        "		(int)X_Face, (int)X_Pname, (float)X_Param);"
        
        NATIVE_glMaterialfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count) n = X_Param.Count;"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param[i];"
        "    AL4_OpenGL.gl.glMaterialfv((int)X_Face, (int)X_Pname, p);"
        
        NATIVE_glMaterialiv = @
        "    int[] p = new int[3];"
        "    int n = 3;"
        "    if (n > X_Param.Count) n = X_Param.Count;"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (int)X_Param[i];"
        "    AL4_OpenGL.gl.glMaterialiv((int)X_Face, (int)X_Pname, p);"
        
        NATIVE_glColorMaterial = @
        "    AL4_OpenGL.gl.glColorMaterial((int)X_Face, (int)X_Mode);"
        
        NATIVE_glFogi = @
        "    AL4_OpenGL.gl.glFogi((int)X_Pname, (int)X_Param);"
        
        NATIVE_glFogf = @
        "    AL4_OpenGL.gl.glFogf((int)X_Pname, (float)X_Param);"
        
        NATIVE_glFogfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count) n = X_Param.Count;"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param[i];"
        "    AL4_OpenGL.gl.glFogfv((int)X_Pname, p);"
        
        NATIVE_gluNewQuadric = @
        "    RESULT = AL4_OpenGL.do_gluNewQuadric();"
        
        NATIVE_gluDeleteQuadric = @
        "    AL4_OpenGL.do_gluDeleteQuadric((int)X_Obj);"
        
        NATIVE_gluQuadricDrawStyle = @
        "    AL4_OpenGL.gl.gluQuadricDrawStyle(AL4_OpenGL.quadric((int)X_Obj),"
        "       (int)X_Style);"
        
        NATIVE_gluQuadricOrientation = @
        "    AL4_OpenGL.gl.gluQuadricOrientation("
        "		AL4_OpenGL.quadric((int)X_Obj), (int)X_Orient);"
        
        NATIVE_gluQuadricTexture = @
        "    AL4_OpenGL.gl.gluQuadricTexture(AL4_OpenGL.quadric((int)X_Obj),"
        "       (byte)X_Texture_c);"
        
        NATIVE_gluQuadricNormals = @
        "    AL4_OpenGL.gl.gluQuadricNormals(AL4_OpenGL.quadric((int)X_Obj),"
        "       (int)X_Normals);"
        
        NATIVE_gluCylinder = @
        "    AL4_OpenGL.gl.gluCylinder(AL4_OpenGL.quadric((int)X_Obj),"
        "       X_Base_r, X_Top_r, X_Height, (int)X_Slices, (int)X_Stacks);"
        
        NATIVE_gluDisk = @
        "    AL4_OpenGL.gl.gluDisk(AL4_OpenGL.quadric((int)X_Obj), X_Inner_r,"
        "       X_Outer_r, (int)X_Slices, (int)X_Loops);"
        
        NATIVE_gluPartialDisk = @
        "    AL4_OpenGL.gl.gluPartialDisk(AL4_OpenGL.quadric((int)X_Obj),"
        "       X_Inner_r, X_Outer_r, "
        "		(int)X_Slices, (int)X_Loops, X_Start_a, X_Sweep_a);"
        
        NATIVE_gluSphere = @
        "    AL4_OpenGL.gl.gluSphere(AL4_OpenGL.quadric((int)X_Obj), X_Radius,"
        "       (int)X_Slices, (int)X_Stacks);"
        
        
        
        .
    */
    
    private static IntPtr mhModuleGL  = System.IntPtr.Zero;
    private static IntPtr mhModuleGLU = System.IntPtr.Zero;
    private static IntPtr mhModuleGDI = System.IntPtr.Zero;
    
    public static Delegate GetDelegate( String functionName, Type delegateType, 
            ref bool foundFunction )
    {
        foundFunction = false;

        IntPtr intPtr = IntPtr.Zero;


        // OPENGL32.DLL
        
        if (mhModuleGL == null)
        {
            mhModuleGL  = GL.Kernel32_LoadLibrary( "opengl32.dll" );
            mhModuleGLU = GL.Kernel32_LoadLibrary( "glu32.dll" );
            mhModuleGDI = GL.Kernel32_LoadLibrary( "gdi32.dll" );
        }

        intPtr = GL.Kernel32_GetProcAddress( mhModuleGL, functionName );
        
        if (IntPtr.Zero != intPtr)
        {
            foundFunction = true;

            Delegate delegateFromFunctionPointer = 
                System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer( intPtr, delegateType );

            return (delegateFromFunctionPointer);
        }


        // GLU32.DLL

        intPtr = GL.Kernel32_GetProcAddress( mhModuleGLU, functionName );
        
        if (IntPtr.Zero != intPtr)
        {
            foundFunction = true;

            Delegate delegateFromFunctionPointer =
                System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(intPtr, delegateType);

            return (delegateFromFunctionPointer);
        }


        // GDI32.DLL
        
        intPtr = GL.Kernel32_GetProcAddress( mhModuleGDI, functionName );
        
        if (IntPtr.Zero != intPtr)
        {
            foundFunction = true;

            Delegate delegateFromFunctionPointer =
                System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(intPtr, delegateType);

            return (delegateFromFunctionPointer);
        }


        // OPENGL extension function (via wglGetProcAddress())

        intPtr = GL.OpenGL32_wglGetProcAddress( functionName );
        
        if (IntPtr.Zero != intPtr)
        {
            foundFunction = true;

            Delegate delegateFromFunctionPointer =
                System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(intPtr, delegateType);

            return (delegateFromFunctionPointer);
        }


        // Failed to find a function

        return ((Delegate)null);
    }

    
    
    
}


/*
END
*/
