Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Exploring OpenGL - 2D Environment

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin Exploring OpenGL - 2D Environment

    Started this thread because I think one should learn to crawl before running. Most of the OpenGL code examples I've seen have few comments and fewer explanations of why things work the way they do. Even the following code lacks in the latter, simply because I don't know.

    Anyway, I'll be adding to this thread as time passes. Others are welcome to add here also.

    Code:
    '=======================================================================
    '                            OPENGL FUNCTIONS USED
    '=======================================================================
    ' glViewport()
    ' glMatrixMode()
    ' glLoadIdentity
    ' gluOrtho2D()
    ' glMatrixMode()
    ' glLoadIdentity
    ' glclear()
    ' glPushMatrix
    ' glTranslatef()
    ' glColor3Ub()
    ' glRectI()
    ' glPopMatrix
    ' glFlush
    '=========================================================================
    '                            WINDOWS FUNCTIONS USED
    '=========================================================================
    ' GetDc
    ' ReleaseDc
    ' ChoosePixelFormat
    ' SetPixelFormat
    ' wglCreateContext
    ' wglMakeCurrent
    ' wglDeleteContext
    '=========================================================================
    
    #COMPILE EXE
    
    DEFLNG A - Z
    
    #INCLUDE "WIN32API.INC"
    #INCLUDE "gl.inc"
    #INCLUDE "glu.inc"
    
    TYPE OglFlag_STRUCT
      EndProg     AS BIT * 1 IN BYTE
      MouseClk    AS BIT * 1
      OglBtnDead  AS BIT * 1
    END TYPE
    
    TYPE Single2_STRUCT
      Mx  AS SINGLE
      My  AS SINGLE
    END TYPE
    
    TYPE Mouse_STRUCT
      Single2_STRUCT
    END TYPE
    
    
    MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                              '   correctly while in 2dimensional mode
    
    %GFX_WIN     =    5
    %BTN_END     =    6
    %BTN_OGL     =    7
    
    
    %OGL_ERROR   = %WM_USER + 500
    
    GLOBAL tFlags AS OglFlag_STRUCT
    GLOBAL tMouse AS Mouse_STRUCT
    
    DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
    DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
    DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                GfxDc AS DWORD, Wide AS LONG, High AS LONG)
    
    DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                            BYVAL GfxHndl AS DWORD)
    
    DECLARE SUB OglRenderImage(BYVAL X1 AS LONG, BYVAL Y1 AS LONG, BYVAL X2 AS LONG, _
                               BYVAL Y2 AS LONG, BYVAL GfxDc AS DWORD)
    
    DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
    
    
    DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
    
    
    DECLARE FUNCTION PBMAIN() AS LONG
    DECLARE CALLBACK FUNCTION Main_CB()
    
    FUNCTION PBMAIN()
    
    LOCAL hDlg  AS DWORD
    
    LOCAL Txt AS STRING
    
    Txt$ = "Click mouse on window to move red rectangle"
    
    DIALOG NEW 0, "Exploring Ogl - 2D Space", , , 201, 131, _
                            %WS_POPUP OR %WS_BORDER _
                            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                            %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                            %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                            %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
    
    CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                            %WS_CHILD OR _
                                            %WS_VISIBLE OR %SS_LEFT OR %SS_CENTERIMAGE OR _
                                            %SS_NOPREFIX OR %SS_NOTIFY _
                                            OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
    
    CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
      OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
      %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
      %WS_EX_LTRREADING
    
    CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl", 120, 95, 75, 20, _
      %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
      OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
      %WS_EX_LTRREADING
    
    DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
    
    DIALOG SHOW MODAL hDlg, CALL Main_CB
    
    END FUNCTION
    
    '------------------------------------------------------------
    '------------------------------------------------------------
    
    CALLBACK FUNCTION Main_CB()
    
    LOCAL lParam AS LONG
    LOCAL wParam AS LONG
    
    SELECT CASE AS LONG CBMSG
    
      wParam = CBWPARAM
    
      CASE %WM_COMMAND
        wParam = CBCTLMSG
        SELECT CASE AS LONG wParam
          CASE %BN_CLICKED, %STN_CLICKED, 1
            SELECT CASE AS LONG CBCTL
              CASE %GFX_WIN
                tFlags.MouseClk = 1
                IF tFlags.OglBtnDead = 0 THEN
                  CONTROL DISABLE CBHNDL, %BTN_OGL
                  tFlags.OglBtnDead = 1
                END IF
                CALL RunOgl(CBHNDL)
                FUNCTION = 1
                EXIT FUNCTION
    
              CASE %BTN_END
                tFlags.EndProg = 1
                CALL RunOgl(CBHNDL)
                DIALOG END CBHNDL
                FUNCTION = 1
                EXIT FUNCTION
    
              CASE %BTN_OGL
                CONTROL DISABLE CBHNDL, %BTN_OGL
                tFlags.OglBtnDead = 1
                CALL RunOgl(CBHNDL)
                FUNCTION = 1
                EXIT FUNCTION
    
            END SELECT
        END SELECT
    
      CASE %WM_DESTROY
        IF tFlags.EndProg THEN EXIT SELECT
        tFlags.EndProg = 1
        CALL RunOgl(CBHNDL)
    
      CASE %OGL_ERROR
        SELECT CASE wParam
          CASE 1
            MSGBOX "Could not find matching pixel format"
          CASE 2
            MSGBOX "Could not set selected pixel format"
          CASE 3
            MSGBOX "Could not create rendering context"
          CASE 4
            MSGBOX "Could not make rendering context current.  Defined window may not" _
                   + " support it"
        END SELECT
        DIALOG END CBHNDL
    END SELECT
    
    END FUNCTION
    
    '------------------------------------------------------------
    '------------------------------------------------------------
    
    SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
    
    '==============================================================
    ' This is the 1st step in setting up windows for OpenGl support
    ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
    ' graphics
    '==============================================================
    
    pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
    pfd.nversion = 1
    pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
    pfd.dwlayermask = %PFD_MAIN_PLANE
    pfd.ipixeltype = %PFD_TYPE_RGBA
    pfd.ccolorbits = 24
    pfd.cdepthbits = 24
    pfd.caccumbits = 0
    pfd.cstencilbits = 0
    
    END SUB
    
    '---------------------------------------------------------------
    '---------------------------------------------------------------
    
    SUB RunOgl(BYVAL Hndl AS DWORD)
    
    STATIC Wide  AS LONG
    STATIC High  AS LONG
    
    LOCAL X     AS LONG
    LOCAL Y     AS LONG
    LOCAL X1    AS LONG
    LOCAL Y1    AS LONG
    
    STATIC GfxDC     AS DWORD
    STATIC OglRc     AS DWORD
    STATIC GfxHndl   AS DWORD
    
    LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
    
    IF ISFALSE(GfxDc) THEN
      IF tFlags.EndProg THEN EXIT SUB
    
      CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
      CALL OglPixFormat(tPixFmt)
    
      OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
    
      IF OglRc = 0 THEN EXIT SUB
    
      CALL SetOglWindow(Wide, High)
    
      X = (Wide \ 2) - 5
      Y = (High \ 2) - 5
      X1 = X + 5
      Y1 = Y + 5
    
    END IF
    
    IF tFlags.EndProg THEN
      CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
      EXIT SUB
    END IF
    
    '==========================================================
    ' Since the OpenGL graphics origin is at the lower left
    ' corner of the drawing window, the mouse "y" coordinate
    ' must be adjusted to produce the correct display location
    '==========================================================
    
    IF tFlags.MouseClk THEN
      CALL Mouse(GfxHndl, Hndl)
      X = tMouse.Mx - 5
      Y = High - tMouse.My - 5
      X1 = X + 5
      Y1 = Y + 5
      tFlags.MouseClk = 0
    END IF
    
    CALL OglRenderImage(X, Y, X1, Y1, GfxDc)
    
    END SUB
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                        tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
    
    '================================================================
    '  This is the second step for OpenGL support
    '  ChoosePixelFormat selects a pixel format that matches that
    '  described in the PIXELFORMATDESCRIPTOR structure.
    '
    '  Each step is the setup is quried because not all windows support
    '  OpenGL rendering
    '================================================================
    
    LOCAL PixFormat AS DWORD
    LOCAL OglRc     AS DWORD
    
    LOCAL T AS LONG
    
    PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
    
    IF ISFALSE (PixFormat) THEN
      DIALOG POST Hndl, %OGL_ERROR, 1, 0
      EXIT FUNCTION
    END IF
    
    t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
    
    IF ISFALSE(t) THEN
      DIALOG POST Hndl, %OGL_ERROR, 2, 0
      EXIT FUNCTION
    END IF
    
    OglRc = wglCreateContext(GfxDc)
    
    IF ISFALSE(OglRc) THEN
      DIALOG POST Hndl, %OGL_ERROR, 3, 0
      EXIT FUNCTION
    END IF
    
    t = wglMakeCurrent(GfxDc, OglRc)
    
    IF ISFALSE(t) THEN
      DIALOG POST Hndl, %OGL_ERROR, 4, 0
      EXIT FUNCTION
    END IF
    
    SetOglPipe = OglRc
    END FUNCTION
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG)
    
    LOCAL ClearClr AS DWORD
    
    '=================================================================
    ' This defines the graphics environment.
    ' Getting this correct is crucial to using OpenGL.
    '
    ' gluOrtho2D is equivalent to using glOrtho with the FAR
    ' parameter set to -1 and the NEAR parameter set to 1
    '=================================================================
    
    ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
               %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
    
    glViewport(0, 0, Wide, High)
    glMatrixMode(%GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, Wide, 0, High)
    glMatrixMode(%GL_MODELVIEW)
    glLoadIdentity()
    glClear(ClearClr)
    
    
    END SUB
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
    
    wglMakeCurrent(0, 0)
    wglDeleteContext(OglRc)
    ReleaseDc(GfxHndl,GfxDc)
    
    END SUB
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                        GfxDc AS DWORD, Wide AS LONG, High AS LONG)
    
    CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
    CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
    DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
    
    GfxDc = GetDc(GfxHndl)
    
    END SUB
    
    '-----------------------------------------------------------------
    '-----------------------------------------------------------------
    
    SUB OglRenderImage(BYVAL X1 AS LONG, BYVAL Y1 AS LONG, BYVAL X2 AS LONG, _
                       BYVAL Y2 AS LONG, BYVAL GfxDc AS DWORD)
    
    '==================================================================
    ' This draws the 2d picture.
    ' glClear must be used when tracking mouse clicks on the drawing window
    ' otherwise crazy images are produced.
    '
    ' The glPush/PopMatrix functions are used to reduce calculation errors
    ' when moving the red rectangle around.  Without those functions active
    ' errors begin to accumulate and the rectangle doesn't follow the mouse
    ' correctly.
    '
    ' glRectI produces a filled red rectangle at the specified coordinates.
    '==================================================================
    
    LOCAL ClearClr AS DWORD
    
    ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
               %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
    
    glPushMatrix
      glTranslatef(GL_FAC, GL_FAC, 0.0)
      glColor3Ub(255, 0, 0)
      glRectI(X1, Y1, X2, Y2)
    glPopMatrix
    
    SwapBuffers(GfxDc)
    
    glClear(ClearClr)
    
    glFlush
    
    END SUB
    
    '------------------------------------------------------------------
    '------------------------------------------------------------------
    
    SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
    
    LOCAL tPoint AS POINT
    
    GetCursorPos(tPoint)
    ScreenToClient(GfxHndl, tPoint)
    
    tMouse.Mx = tPoint.X
    tMouse.My = tPoint.Y
    
    END SUB
    Last edited by Walt Decker; 10 Jun 2010, 12:25 PM.
    Walt Decker

  • #2
    Ogl 2D Space Points and Lines

    Here I examine points and lines in OpenGl 2D space.

    The following code looks at the effect of glEnable, glHint, glLineWidth, and glBegin has on points in an array.

    glEnable(%GL_LINE_SMOOTH) appears to have little effect. This may be that I'm working in 2D space or that the color table is simply not large enough for antialiasing to be effective.

    Notice the effect glBegin(%GL_LINE_LOOP) has compared to glBegin(%GL_LINES).

    Code:
    '=======================================================================
    '                            OPENGL FUNCTIONS USED
    '=======================================================================
    ' glViewport()
    ' glMatrixMode()
    ' glLoadIdentity
    ' gluOrtho2D()
    ' glMatrixMode()
    ' glLoadIdentity
    ' glclear()
    ' glPushMatrix
    ' glTranslatef()
    ' glColor3Ub()
    ' glBegin()
    ' glEnd
    ' glVertex2I()
    ' glPopMatrix
    ' glFlush
    ' glLineWidth()
    ' glEnable()
    ' glHint()
    '=========================================================================
    '                            WINDOWS FUNCTIONS USED
    '=========================================================================
    ' GetDc
    ' ReleaseDc
    ' ChoosePixelFormat
    ' SetPixelFormat
    ' wglCreateContext
    ' wglMakeCurrent
    ' wglDeleteContext
    '=========================================================================
    
    #COMPILE EXE
    
    DEFLNG A - Z
    
    #INCLUDE "WIN32API.INC"
    #INCLUDE "gl.inc"
    #INCLUDE "glu.inc"
    
    TYPE OglFlag_STRUCT
      EndProg     AS BIT * 1 IN BYTE
      MouseClk    AS BIT * 1
      OglBtnDead  AS BIT * 1
    END TYPE
    
    TYPE Single2_STRUCT
      Mx  AS SINGLE
      My  AS SINGLE
    END TYPE
    
    TYPE Mouse_STRUCT
      Single2_STRUCT
    END TYPE
    
    
    MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                              '   correctly while in 2dimensional mode
    
    %GFX_WIN     =    5
    %BTN_END     =    6
    %BTN_OGL     =    7
    
    
    %OGL_ERROR   = %WM_USER + 500
    
    GLOBAL tFlags AS OglFlag_STRUCT
    GLOBAL tMouse AS Mouse_STRUCT
    
    DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
    DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
    DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                GfxDc AS DWORD, Wide AS LONG, High AS LONG)
    
    DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                            BYVAL GfxHndl AS DWORD)
    
    DECLARE SUB OglRenderImage(glArray() AS DWORD, glPArray() AS DWORD, BYVAL GfxDc AS DWORD)
    
    DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
    
    
    DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
    
    
    DECLARE FUNCTION PBMAIN() AS LONG
    DECLARE CALLBACK FUNCTION Main_CB()
    
    FUNCTION PBMAIN()
    
    LOCAL hDlg  AS DWORD
    
    LOCAL Txt AS STRING
    
    Txt$ = "Click mouse on window to draw a line"
    
    DIALOG NEW 0, "Exploring Ogl - 2D Space Points and Lines", , , 201, 131, _
                            %WS_POPUP OR %WS_BORDER _
                            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                            %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                            %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                            %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
    
    CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                            %WS_CHILD OR _
                                            %WS_VISIBLE OR %SS_LEFT OR %SS_CENTERIMAGE OR _
                                            %SS_NOPREFIX OR %SS_NOTIFY _
                                            OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
    
    CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
      OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
      %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
      %WS_EX_LTRREADING
    
    CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl", 120, 95, 75, 20, _
      %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
      OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
      %WS_EX_LTRREADING
    
    DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
    
    DIALOG SHOW MODAL hDlg, CALL Main_CB
    
    END FUNCTION
    
    '------------------------------------------------------------
    '------------------------------------------------------------
    
    CALLBACK FUNCTION Main_CB()
    
    LOCAL lParam AS LONG
    LOCAL wParam AS LONG
    
    SELECT CASE AS LONG CBMSG
    
      wParam = CBWPARAM
      CASE %WM_INITDIALOG
        CONTROL DISABLE CBHNDL, %BTN_OGL
    
      CASE %WM_COMMAND
        wParam = CBCTLMSG
        SELECT CASE AS LONG wParam
          CASE %BN_CLICKED, %STN_CLICKED, 1
            SELECT CASE AS LONG CBCTL
              CASE %GFX_WIN
                tFlags.MouseClk = 1
                IF tFlags.OglBtnDead = 0 THEN
                  CONTROL DISABLE CBHNDL, %BTN_OGL
                  tFlags.OglBtnDead = 1
                END IF
                CALL RunOgl(CBHNDL)
                FUNCTION = 1
                EXIT FUNCTION
    
              CASE %BTN_END
                tFlags.EndProg = 1
                CALL RunOgl(CBHNDL)
                DIALOG END CBHNDL
                FUNCTION = 1
                EXIT FUNCTION
    
              CASE %BTN_OGL
                CONTROL DISABLE CBHNDL, %BTN_OGL
                tFlags.OglBtnDead = 1
                CALL RunOgl(CBHNDL)
                FUNCTION = 1
                EXIT FUNCTION
    
            END SELECT
        END SELECT
    
      CASE %WM_DESTROY
        IF tFlags.EndProg THEN EXIT SELECT
        tFlags.EndProg = 1
        CALL RunOgl(CBHNDL)
    
      CASE %OGL_ERROR
        SELECT CASE wParam
          CASE 1
            MSGBOX "Could not find matching pixel format"
          CASE 2
            MSGBOX "Could not set selected pixel format"
          CASE 3
            MSGBOX "Could not create rendering context"
          CASE 4
            MSGBOX "Could not make rendering context current.  Defined window may not" _
                   + " support it"
        END SELECT
        DIALOG END CBHNDL
    END SELECT
    
    END FUNCTION
    
    '------------------------------------------------------------
    '------------------------------------------------------------
    
    SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
    
    '==============================================================
    ' This is the 1st step in setting up windows for OpenGl support
    ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
    ' graphics
    '==============================================================
    
    pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
    pfd.nversion = 1
    pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
    pfd.dwlayermask = %PFD_MAIN_PLANE
    pfd.ipixeltype = %PFD_TYPE_RGBA
    pfd.ccolorbits = 24
    pfd.cdepthbits = 24
    pfd.caccumbits = 0
    pfd.cstencilbits = 0
    
    END SUB
    
    '---------------------------------------------------------------
    '---------------------------------------------------------------
    
    SUB RunOgl(BYVAL Hndl AS DWORD)
    
    STATIC Wide  AS LONG
    STATIC High  AS LONG
    
    LOCAL X     AS LONG
    LOCAL Y     AS LONG
    LOCAL X1    AS LONG
    LOCAL Y1    AS LONG
    
    STATIC GfxDC     AS DWORD
    STATIC OglRc     AS DWORD
    STATIC GfxHndl   AS DWORD
    STATIC AryCnt    AS DWORD
    STATIC PntCnt    AS DWORD
    
    STATIC glLArray() AS DWORD
    STATIC glPArray() AS DWORD
    
    LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
    
    DIM glPArray(1 TO 2, 1 TO 1)
    
    IF ISFALSE(GfxDc) THEN
      IF tFlags.EndProg THEN EXIT SUB
    
      CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
      CALL OglPixFormat(tPixFmt)
    
      OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
    
      IF OglRc = 0 THEN EXIT SUB
    
      CALL SetOglWindow(Wide, High)
    
    END IF
    
    IF tFlags.EndProg THEN
      CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
      EXIT SUB
    END IF
    
    IF tFlags.MouseClk THEN
      CALL Mouse(GfxHndl, Hndl)
      INCR AryCnt
      INCR PntCnt                                   '===========================================
      REDIM PRESERVE glLArray(1 TO 2, 1 TO AryCnt)   ' In order to make the lines connect we have
      REDIM PRESERVE glPArray(1 TO 2, 1 TO PntCnt)   ' to set the current array element to the
      IF AryCnt > 2 THEN                             ' previous array element
        glLArray(1, AryCnt) = glLArray(1, AryCnt - 1)'===========================================
        glLArray(2, AryCnt) = glLArray(2, AryCnt - 1)
        INCR AryCnt
        REDIM PRESERVE glLArray(1 TO 2, 1 TO AryCnt) '=============================================
      END IF                                  ' Since the OpenGL graphics origin is at the lower left
      glLArray(1, AryCnt) = tMouse.Mx         ' corner of the drawing window, the mouse "y" coordinate
      glLArray(2, AryCnt) = High - tMouse.My  ' must be adjusted to produce the correct display
      glPArray(1, PntCnt) = tMouse.Mx         ' location
      glParray(2, PntCnt) = High - tMouse.My  '=====================================================
      tFlags.MouseClk = 0
    END IF
    
    CALL OglRenderImage(glLArray(), glPArray(), GfxDc)
    
    END SUB
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                        tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
    
    '================================================================
    '  This is the second step for OpenGL support
    '  ChoosePixelFormat selects a pixel format that matches that
    '  described in the PIXELFORMATDESCRIPTOR structure.
    '
    '  Each step is the setup is quried because not all windows support
    '  OpenGL rendering
    '================================================================
    
    LOCAL PixFormat AS DWORD
    LOCAL OglRc     AS DWORD
    
    LOCAL T AS LONG
    
    PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
    
    IF ISFALSE (PixFormat) THEN
      DIALOG POST Hndl, %OGL_ERROR, 1, 0
      EXIT FUNCTION
    END IF
    
    t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
    
    IF ISFALSE(t) THEN
      DIALOG POST Hndl, %OGL_ERROR, 2, 0
      EXIT FUNCTION
    END IF
    
    OglRc = wglCreateContext(GfxDc)
    
    IF ISFALSE(OglRc) THEN
      DIALOG POST Hndl, %OGL_ERROR, 3, 0
      EXIT FUNCTION
    END IF
    
    t = wglMakeCurrent(GfxDc, OglRc)
    
    IF ISFALSE(t) THEN
      DIALOG POST Hndl, %OGL_ERROR, 4, 0
      EXIT FUNCTION
    END IF
    
    SetOglPipe = OglRc
    END FUNCTION
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG)
    
    LOCAL ClearClr AS DWORD
    
    '=================================================================
    ' This defines the graphics environment.
    ' Getting this correct is crucial to using OpenGL.
    '
    ' gluOrtho2D is equivalent to using glOrtho with the FAR
    ' parameter set to -1 and the NEAR parameter set to 1
    '=================================================================
    
    ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
               %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
    
    glViewport(0, 0, Wide, High)
    glMatrixMode(%GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, Wide, 0, High)
    glMatrixMode(%GL_MODELVIEW)
    glLoadIdentity()
    glClear(ClearClr)
    
    
    END SUB
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
    
    wglMakeCurrent(0, 0)
    wglDeleteContext(OglRc)
    ReleaseDc(GfxHndl,GfxDc)
    
    END SUB
    
    '----------------------------------------------------------------
    '----------------------------------------------------------------
    
    SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                        GfxDc AS DWORD, Wide AS LONG, High AS LONG)
    
    CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
    CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
    DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
    
    GfxDc = GetDc(GfxHndl)
    
    END SUB
    
    '-----------------------------------------------------------------
    '-----------------------------------------------------------------
    
    SUB OglRenderImage(glArray() AS DWORD, glPArray() AS DWORD, BYVAL GfxDc AS DWORD)
    
    '==================================================================
    ' This draws the 2d picture.
    ' glClear must be used when tracking mouse clicks on the drawing window
    ' otherwise crazy images are produced.
    '
    ' The glPush/PopMatrix functions are used to reduce calculation errors
    ' when drawing the array.  Without those functions active
    ' errors begin to accumulate and the lines don't follow the mouse
    ' correctly.
    '
    ' glBegin() marks the beginning of the drwaing operation; glEnd marks
    ' the end of the drawing operation. With the %GL_LINES parameter, connected
    ' lines are drawn. With the %GL_LINE_LOOP parameter, connected lines are
    ' drawn and a line is drawn from the last point back to the first.
    '
    ' glVertex2I() specifies that there are 2 integer values to process.
    '==================================================================
    
    LOCAL ClearClr AS DWORD
    
    ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
               %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
    
    
    glPushMatrix
      glBegin(%GL_POINTS)
        glColor3Ub(255, 200, 255)
        FOR I = 1 TO UBOUND(glArray, 2)
          glVertex2I(glArray(1, I) - 5, glArray(2, I) - 5)
        NEXT I
      glEnd
    glPopMatrix
    
    glLineWidth(0.0)
    glPushMatrix
      glBegin(%GL_LINES)
        glColor3Ub(255, 255, 0)
        FOR I = 1 TO UBOUND(glArray, 2)
          glVertex2I(glArray(1, I) + 5, glArray(2, I) + 5)
        NEXT I
      glEnd
    glPopMatrix
    
    glLineWidth(2.0)
    glEnable(%GL_LINE_SMOOTH)
    glHint(%GL_LINE_SMOOTH_HINT, %GL_NICEST)
    
    glPushMatrix
      glColor3Ub(255, 255, 255)
      glBegin(%GL_LINE_LOOP)
        FOR I = 1 TO UBOUND(glPArray, 2)
          glVertex2I(glPArray(1, I), glParray(2, I))
        NEXT I
      glEnd
    glPopMatrix
    
    SwapBuffers(GfxDc)
    
    glClear(ClearClr)
    glLineWidth(0.0)
    glDisable(%GL_LINE_SMOOTH)
    
    glFlush
    
    END SUB
    
    '------------------------------------------------------------------
    '------------------------------------------------------------------
    
    SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
    
    LOCAL tPoint AS POINT
    
    GetCursorPos(tPoint)
    ScreenToClient(GfxHndl, tPoint)
    
    tMouse.Mx = tPoint.X
    tMouse.My = tPoint.Y
    
    END SUB
    Try replacing glBegin(%GL_LINE_LOOP) with:

    GL_LINE_STRIP

    Draws a connected group of line segments from the first vertex to the last. Vertices n and n+1 define line n. N – 1 lines are drawn.

    GL_TRIANGLES

    Treats each triplet of vertices as an independent triangle. Vertices 3n – 2, 3n –1, and 3n define triangle n. N/3 triangles are drawn.

    GL_TRIANGLE_STRIP

    Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertices. For odd n, vertices n, n + 1, and n + 2 define triangle n. For even n, vertices n + 1, n, and n + 2 define triangle n. N – 2 triangles are drawn.

    GL_TRIANGLE_FAN

    Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertices. Vertices 1, n + 1, and n + 2 define triangle n. N – 2 triangles are drawn.

    GL_QUADS

    Treats each group of four vertices as an independent quadrilateral. Vertices 4n – 3, 4n – 2, 4n – 1, and 4n define quadrilateral n. N/4 quadrilaterals are drawn.

    GL_QUAD_STRIP

    Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair of vertices presented after the first pair. Vertices 2n – 1, 2n, 2n + 2, and 2n + 1 define quadrilateral n. N quadrilaterals are drawn. Note that the order in which vertices are used to construct a quadrilateral from strip data is different from that used with independent data.

    GL_POLYGON

    Draws a single, convex polygon. Vertices 1 through N define this polygon.
    Last edited by Walt Decker; 10 Jun 2010, 12:27 PM. Reason: give hints
    Walt Decker

    Comment


    • #3
      Parallel Projection

      The original title of this thread is "Exploring OpenGl - 2D Environment." It should just be "Exploring OpenGl."

      Anyway, with this post I'm examining OpenGl's 3D environment in parallel projection mode, i. e., orthographic projection.

      According to windows documentation of function glOrtho(), if the "NEAR" parameter is negative the face is behind the viewer. That is misleading. Logically, if a face, object, whatever is behind the viewer, it can't be seen. Actually, if the "NEAR" face is negative it is at the front of the object.

      Also, according to documentation, both the "NEAR and "FAR" parameters can be either negative or positive. So far, I have had no success displaying objects when both parameters are negative or positive. It's probably because I just haven't stumbled on the correct combination with the translate() and rotate() functions.

      When setting up a model one has to consider the values given for the "NEAR" and "FAR" parameters. In general:

      if "NEAR" is negative and "FAR" is positive and glTranslate() is used, the absolute value of the "z" parameter of glTranslate() plus the "z" value of glVertex() cannot exceed the range of "Near/Far". If it does, nothing is displayed.

      if "NEAR" is positive and "FAR" is negative and glTranslate() is used, the "z" parameter of glTranslate() plus the "z" value of glVertex() cannot exceed the "FAR" value.

      Anyway, here's some code to play with.

      Code:
      '=======================================================================
      '                            OPENGL FUNCTIONS USED
      '=======================================================================
      ' glViewport()
      ' glMatrixMode()
      ' glLoadIdentity
      ' glOrtho()
      ' glMatrixMode()
      ' glLoadIdentity
      ' glclear()
      ' glPushMatrix
      ' glTranslatef()
      ' glColor3Ub()
      ' glBegin()
      ' glEnd
      ' glVertex3F()
      ' glPopMatrix
      ' glFlush
      ' glLineWidth()
      ' glEnable()
      ' glHint()
      '=========================================================================
      '                            WINDOWS FUNCTIONS USED
      '=========================================================================
      ' GetDc
      ' ReleaseDc
      ' ChoosePixelFormat
      ' SetPixelFormat
      ' wglCreateContext
      ' wglMakeCurrent
      ' wglDeleteContext
      '=========================================================================
      
      #COMPILE EXE
      
      DEFLNG A - Z
      
      #INCLUDE "WIN32API.INC"
      #INCLUDE "gl.inc"
      #INCLUDE "glu.inc"
      
      TYPE OglFlag_STRUCT
        EndProg     AS BIT * 1 IN BYTE
        MouseClk    AS BIT * 1
        OglBtnDead  AS BIT * 1
        RunGlDemo   AS BIT * 1
      END TYPE
      
      TYPE Single2_STRUCT
        Mx  AS SINGLE
        My  AS SINGLE
      END TYPE
      
      TYPE Mouse_STRUCT
        Single2_STRUCT
      END TYPE
      
      
      MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                '   correctly while in 2dimensional mode
      
      %GFX_WIN     =    5
      %BTN_END     =    6
      %BTN_OGL     =    7
      
      
      %OGL_ERROR   = %WM_USER + 500
      
      GLOBAL tFlags AS OglFlag_STRUCT
      GLOBAL tMouse AS Mouse_STRUCT
      
      DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
      DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
      DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                  GfxDc AS DWORD, Wide AS LONG, High AS LONG)
      
      DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                              BYVAL GfxHndl AS DWORD)
      
      DECLARE SUB OglRenderImage(glArray() AS DWORD, glPArray() AS DWORD, BYVAL GfxDc AS DWORD)
      
      DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
      
      
      DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                  tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
      
      
      DECLARE FUNCTION PBMAIN() AS LONG
      DECLARE CALLBACK FUNCTION Main_CB()
      
      FUNCTION PBMAIN()
      
      LOCAL hDlg  AS DWORD
      
      LOCAL Txt AS STRING
      
      Txt$ = "Click mouse on window to draw a line and a quadratic" + _
             $CRLF + "Click mouse on window to rotate the cube."
      
      DIALOG NEW 0, "Exploring Ogl - 3D Parallel Projection", , , 201, 131, _
                              %WS_POPUP OR %WS_BORDER _
                              OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                              %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                              %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                              %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
      
      CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                              %WS_CHILD OR _
                                              %WS_VISIBLE OR %SS_CENTER OR _
                                              %SS_NOPREFIX OR %SS_NOTIFY _
                                              OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
      
      CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
        OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
        %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
        %WS_EX_LTRREADING
      
      CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
        %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
        OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
        %WS_EX_LTRREADING
      
      DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
      
      DIALOG SHOW MODAL hDlg, CALL Main_CB
      
      END FUNCTION
      
      '------------------------------------------------------------
      '------------------------------------------------------------
      
      CALLBACK FUNCTION Main_CB()
      
      LOCAL lParam AS LONG
      LOCAL wParam AS LONG
      
      SELECT CASE AS LONG CBMSG
      
        wParam = CBWPARAM
        CASE %WM_INITDIALOG
      
        CASE %WM_COMMAND
          wParam = CBCTLMSG
          SELECT CASE AS LONG wParam
            CASE %BN_CLICKED, %STN_CLICKED, 1
              SELECT CASE AS LONG CBCTL
                CASE %GFX_WIN
                  tFlags.MouseClk = 1
                  IF tFlags.RunGlDemo THEN EXIT SELECT
                  CALL RunOgl(CBHNDL)
      
                  FUNCTION = 1
                  EXIT FUNCTION
      
                CASE %BTN_END
                  tFlags.EndProg = 1
                  CALL RunOgl(CBHNDL)
                  DIALOG END CBHNDL
                  FUNCTION = 1
                  EXIT FUNCTION
      
                CASE %BTN_OGL
                  CONTROL DISABLE CBHNDL, %BTN_OGL
                  tFlags.OglBtnDead = 1
                  tFlags.RunGlDemo = 1
                  CALL RunOgl(CBHNDL)
                  FUNCTION = 1
                  EXIT FUNCTION
      
              END SELECT
          END SELECT
      
        CASE %WM_DESTROY
          IF tFlags.EndProg THEN EXIT SELECT
          tFlags.EndProg = 1
          CALL RunOgl(CBHNDL)
      
        CASE %OGL_ERROR
          SELECT CASE wParam
            CASE 1
              MSGBOX "Could not find matching pixel format"
            CASE 2
              MSGBOX "Could not set selected pixel format"
            CASE 3
              MSGBOX "Could not create rendering context"
            CASE 4
              MSGBOX "Could not make rendering context current.  Defined window may not" _
                     + " support it"
          END SELECT
          DIALOG END CBHNDL
      END SELECT
      
      END FUNCTION
      
      '------------------------------------------------------------
      '------------------------------------------------------------
      
      SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
      
      '==============================================================
      ' This is the 1st step in setting up windows for OpenGl support
      ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
      ' graphics
      '==============================================================
      
      pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
      pfd.nversion = 1
      pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
      pfd.dwlayermask = %PFD_MAIN_PLANE
      pfd.ipixeltype = %PFD_TYPE_RGBA
      pfd.ccolorbits = 24
      pfd.cdepthbits = 24
      pfd.caccumbits = 0
      pfd.cstencilbits = 0
      
      END SUB
      
      '---------------------------------------------------------------
      '---------------------------------------------------------------
      
      SUB RunOgl(BYVAL Hndl AS DWORD)
      
      STATIC Wide  AS LONG
      STATIC High  AS LONG
      
      LOCAL X     AS LONG
      LOCAL Y     AS LONG
      LOCAL X1    AS LONG
      LOCAL Y1    AS LONG
      
      STATIC GfxDC     AS DWORD
      STATIC OglRc     AS DWORD
      STATIC GfxHndl   AS DWORD
      STATIC AryCnt    AS DWORD
      STATIC PntCnt    AS DWORD
      
      STATIC glLArray() AS DWORD
      STATIC glPArray() AS DWORD
      
      LOCAL Cube_Matrix() AS SINGLE
      
      LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
      
      DIM glPArray(1 TO 2, 1 TO 1)
      DIM Cube_Matrix(1 TO 1, 1 TO 3)
      
      IF ISFALSE(GfxDc) THEN
        IF tFlags.EndProg THEN EXIT SUB
      
        CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
        CALL OglPixFormat(tPixFmt)
      
        OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
      
        IF OglRc = 0 THEN EXIT SUB
      
        CALL SetOglWindow(Wide, High)
      
      END IF
      
      IF tFlags.EndProg THEN
        CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
        EXIT SUB
      END IF
      
      IF tFlags.MouseClk THEN
        CALL Mouse(GfxHndl, Hndl)
        INCR AryCnt
        INCR PntCnt                                   '===========================================
        REDIM PRESERVE glLArray(1 TO 2, 1 TO AryCnt)   ' In order to make the lines connect we have
        REDIM PRESERVE glPArray(1 TO 2, 1 TO PntCnt)   ' to set the current array element to the
        IF AryCnt > 2 THEN                             ' previous array element
          glLArray(1, AryCnt) = glLArray(1, AryCnt - 1)'===========================================
          glLArray(2, AryCnt) = glLArray(2, AryCnt - 1)
          INCR AryCnt
          REDIM PRESERVE glLArray(1 TO 2, 1 TO AryCnt) '=============================================
        END IF                                  ' Since the OpenGL graphics origin is at the lower left
        glLArray(1, AryCnt) = tMouse.Mx         ' corner of the drawing window, the mouse "y" coordinate
        glLArray(2, AryCnt) = High - tMouse.My  ' must be adjusted to produce the correct display
        glPArray(1, PntCnt) = tMouse.Mx         ' location
        glParray(2, PntCnt) = High - tMouse.My  '=====================================================
        tFlags.MouseClk = 0
      END IF
      
      CALL OglRenderImage(glLArray(), glPArray(), GfxDc)
      IF tFlags.RunGlDemo THEN
        CALL Cube_Data(Cube_Matrix())
        CALL glRunDemo(Cube_Matrix(), GfxDc)
      END IF
      END SUB
      
      '----------------------------------------------------------------
      '----------------------------------------------------------------
      
      FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                          tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
      
      '================================================================
      '  This is the second step for OpenGL support
      '  ChoosePixelFormat selects a pixel format that matches that
      '  described in the PIXELFORMATDESCRIPTOR structure.
      '
      '  Each step is the setup is quried because not all windows support
      '  OpenGL rendering
      '================================================================
      
      LOCAL PixFormat AS DWORD
      LOCAL OglRc     AS DWORD
      
      LOCAL T AS LONG
      
      PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
      
      IF ISFALSE (PixFormat) THEN
        DIALOG POST Hndl, %OGL_ERROR, 1, 0
        EXIT FUNCTION
      END IF
      
      t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
      
      IF ISFALSE(t) THEN
        DIALOG POST Hndl, %OGL_ERROR, 2, 0
        EXIT FUNCTION
      END IF
      
      OglRc = wglCreateContext(GfxDc)
      
      IF ISFALSE(OglRc) THEN
        DIALOG POST Hndl, %OGL_ERROR, 3, 0
        EXIT FUNCTION
      END IF
      
      t = wglMakeCurrent(GfxDc, OglRc)
      
      IF ISFALSE(t) THEN
        DIALOG POST Hndl, %OGL_ERROR, 4, 0
        EXIT FUNCTION
      END IF
      
      SetOglPipe = OglRc
      END FUNCTION
      
      '----------------------------------------------------------------
      '----------------------------------------------------------------
      
      SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG)
      
      LOCAL ClearClr AS DWORD
      
      '=================================================================
      ' This defines the graphics environment.
      ' Getting this correct is crucial to using OpenGL.
      '
      ' gluOrtho2D is equivalent to using glOrtho with the FAR
      ' parameter set to -1 and the NEAR parameter set to 1
      '=================================================================
      
      ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                 %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
      
      glViewport(0, 0, Wide, High)
      'glMatrixMode(%GL_PROJECTION)
      glLoadIdentity()
      glOrtho(0, Wide, 0, High, -100!, 300.000!)
      glMatrixMode(%GL_MODELVIEW)
      glClear(ClearClr)
      
      
      END SUB
      
      '----------------------------------------------------------------
      '----------------------------------------------------------------
      
      SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
      
      wglMakeCurrent(0, 0)
      wglDeleteContext(OglRc)
      ReleaseDc(GfxHndl,GfxDc)
      
      END SUB
      
      '----------------------------------------------------------------
      '----------------------------------------------------------------
      
      SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                          GfxDc AS DWORD, Wide AS LONG, High AS LONG)
      
      CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
      CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
      DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
      
      GfxDc = GetDc(GfxHndl)
      
      END SUB
      
      '-----------------------------------------------------------------
      '-----------------------------------------------------------------
      
      SUB OglRenderImage(glArray() AS DWORD, glPArray() AS DWORD, BYVAL GfxDc AS DWORD)
      
      '==================================================================
      ' This draws the 2d picture.
      ' glClear must be used when tracking mouse clicks on the drawing window
      ' otherwise crazy images are produced.
      '
      ' The glPush/PopMatrix functions are used to reduce calculation errors
      ' when drawing the array.  Without those functions active
      ' errors begin to accumulate and the lines don't follow the mouse
      ' correctly.
      '
      ' glBegin() marks the beginning of the drwaing operation; glEnd marks
      ' the end of the drawing operation. With the %GL_LINES parameter, connected
      ' lines are drawn. With the %GL_LINE_LOOP parameter, connected lines are
      ' drawn and a line is drawn from the last point back to the first.
      '
      '==================================================================
      
      LOCAL ClearClr AS DWORD
      
      ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                 %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
      
      
      glPushMatrix
        glTranslateF(GL_FAC, GL_FAC, -10!)
        glBegin(%GL_POINTS)
          glColor3Ub(255, 200, 255)
          FOR I = 1 TO UBOUND(glArray, 2)
            glVertex3f(glArray(1, I), glArray(2, I), 000!)
          NEXT I
        glEnd
      glPopMatrix
      
      glLineWidth(0.0)
      glPushMatrix
        glTranslateF(GL_FAC, GL_FAC, 100.0)
        glBegin(%GL_LINES)
          glColor3Ub(255, 255, 0)
          FOR I = 1 TO UBOUND(glArray, 2)
            glVertex3f(glArray(1, I), glArray(2, I), -6!)
          NEXT I
        glEnd
      glPopMatrix
      
      glLineWidth(2.0)
      glEnable(%GL_LINE_SMOOTH)
      glHint(%GL_LINE_SMOOTH_HINT, %GL_NICEST)
      
      glPushMatrix
        glTranslateF(GL_FAC, GL_FAC, -50.0)
        glBegin(%GL_QUADS)
          FOR I = 1 TO UBOUND(glPArray, 2)
            glColor3Ub(RND(0, 255), RND(0 ,255), RND(0, 255))
            glVertex3f(glPArray(1, I), glParray(2, I), 100!)
          NEXT I
        glEnd
      glPopMatrix
      
      SwapBuffers(GfxDc)
      
      glClear(ClearClr)
      glLineWidth(0.0)
      glDisable(%GL_LINE_SMOOTH)
      
      glFlush
      
      END SUB
      
      '------------------------------------------------------------------
      '------------------------------------------------------------------
      
      SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
      
      LOCAL tPoint AS POINT
      
      GetCursorPos(tPoint)
      ScreenToClient(GfxHndl, tPoint)
      
      tMouse.Mx = tPoint.X
      tMouse.My = tPoint.Y
      
      END SUB
      
      '-------------------------------------------------------------------
      '-------------------------------------------------------------------
      
      SUB Cube_Data(Cube_Matrix() AS SINGLE)
      
      '--------> Front Face
      '-----  color flag ----
      DATA -99,  0,  0
      '----------------------
      DATA 128,128, 255
      DATA 100, 90, -50
      DATA 150, 90, -50
      DATA 150, 40, -50
      DATA 100, 40, -50
      
      '--------> Left Face
      DATA -99,   0,   0
      DATA 128, 255, 255
      DATA 100,  90, -50
      DATA 130, 110,  50
      DATA 130,  60,  50
      DATA 100,  40, -50
      
      '---------> Top Face
      DATA -99,   0,   0
      DATA 255, 128, 128
      DATA 100,  90, -50
      DATA 130, 110,  50
      DATA 180, 110,  50
      DATA 150,  90, -50
      
      '---------> Right Face
      DATA -99,   0,   0
      DATA 255,   0, 128
      DATA 150,  90, -50
      DATA 180, 110,  50
      DATA 180,  60,  50
      DATA 150,  40, -50
      
      '---------> Back Face
      DATA -99,   0,   0
      DATA 255, 255, 255
      DATA 130, 110,  50
      DATA 180, 110,  50
      DATA 180,  60,  50
      DATA 130,  60,  50
      
      '---------> Bottom Face
      DATA -99,   0,   0
      DATA 255, 255,   0
      DATA 100,  40, -50
      DATA 130,  60,  50
      DATA 180,  60,  50
      DATA 150,  40, -50
      
      D = DATACOUNT \ 3
      
      REDIM Cube_Matrix(1 TO D, 1 TO 3)
      
      J = 0
      
      FOR I = 1 TO DATACOUNT STEP 3
        INCR J
        Cube_Matrix(J, 1) = VAL(READ$(I))
        Cube_Matrix(J, 2) = VAL(READ$(I + 1))
        Cube_Matrix(J, 3) = VAL(READ$(I + 2))
      NEXT I
      
      END SUB
      
      '---------------------------------------------------
      '---------------------------------------------------
      
      SUB glRunDemo(Cube_Matrix() AS SINGLE, BYVAL GfxDc AS DWORD)
      
      '====================================================
      ' This draws the "standard" cube.
      ' Each time the right mouse button is clicked the cube moves
      ' 10 degrees to the left around the Y axis.
      '
      ' By not using glEnable(%GL_DEPTH TEST) it appears that the
      ' viewer is looking into the cube.
      '=====================================================
      
      ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                 %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
      
      
      Again: '
      
      glPushMatrix
      
      '================================================================
      ' In this case glTranslateF(GL_FAC, GL_FAC, 0.0) is not used.  If
      ' that function is used, the cube is translated up and to the right
      ' of the viewing surface.
      '================================================================
      
      glBegin(%GL_QUADS)
        FOR I = 1 TO UBOUND(Cube_Matrix)
          IF Cube_Matrix(I, 1) < 0.0 THEN
            I = I + 1
            glColor3Ub(Cube_Matrix(I, 1), Cube_Matrix(I, 2), Cube_Matrix(I, 3))
            ITERATE FOR
          END IF
          glVertex3f(Cube_Matrix(I, 1), Cube_Matrix(I, 2), Cube_Matrix(I, 3))
        NEXT I
      glEnd
      glPopMatrix
      SwapBuffers(GfxDc)
      glClear(ClearClr)
      
      '=================================================================
      ' The matrix mode is changed to glMatrixMode(%GL_PROJECTION).
      ' If glTranslateF(GL_FAC, GL_FAC, 0.0) is used, the image is eventurally
      ' moved out of viewing range and then back.
      '=================================================================
      
      DO
        DIALOG DOEVENTS
        IF tFlags.EndProg THEN EXIT DO
        IF tFlags.MouseClk THEN
          glMatrixMode(%GL_PROJECTION)
          glRotateF(-10, 0, 1, 0)
          tFlags.MouseClk = 0
          GOTO Again
        END IF
      LOOP
      END SUB
      
      '------------------------------------------------------------------
      '------------------------------------------------------------------
      Last edited by Walt Decker; 10 Jun 2010, 12:29 PM. Reason: correct error in sub CloseOpenGL
      Walt Decker

      Comment


      • #4
        Text in the OpenGL Ortho Environment

        OpenGL has no method of displaying text. This leaves you with two options:
        1 - use one of the windows wiggle functions to display text
        2 - create your own function to display text.

        Using the wiggle functions "wglUseFontBitmaps()" and "wglUseFontOutlines()" is not straight forward. Everything must be just right to do so.

        First you have to select a font to use, then you have to create a bunch of empty rendering lists, one for each character you want to display. Next you have to use one of the wiggle functions to fill the lists. Finally you have to use the lists to render the characters. If you haven't generated the entire character set and used an incorrect offset into the list, either no characters will be rendered or they will be incorrect. If you use an incorrect ogl constant in the glCallLists function no characters will be rendered. If the coordinates aren't correct no text will be rendered.

        The following two apps demonstrate using a wiggle function and creating your own function to display text.

        The first uses "wglUseFontBitmaps()" only. "wglUseFontOutlines()" is not demonstrated simply because I have yet to figure out how to use it in an orthographic environment.

        The second uses a memory bitmap to first render the text then creates an array of verticies to render the text.

        Each are fairly well commented.

        "wglUseFontBitmaps()" code:

        Code:
        '=======================================================================
        '                            OPENGL FUNCTIONS USED
        '=======================================================================
        ' glViewport()
        ' glMatrixMode()
        ' glLoadIdentity
        ' glOrtho()
        ' glMatrixMode()
        ' glclear()
        ' glColor3Ub()
        ' glGenLists()
        ' glRasterPos2F()
        ' glListBase()
        ' glCallLists()
        '=========================================================================
        '                            WINDOWS FUNCTIONS USED
        '=========================================================================
        ' GetDc()
        ' ReleaseDc()
        ' ChoosePixelFormat()
        ' SetPixelFormat()
        ' wglCreateContext()
        ' wglMakeCurrent()
        ' wglDeleteContext()
        ' SwapBuffers()
        ' wglUseFontBitmaps()
        ' CreateFont()
        ' SelectObject()
        ' DeleteObject()
        '=========================================================================
        
        #COMPILE EXE
        #DEBUG DISPLAY ON
        
        DEFLNG A - Z
        
        #INCLUDE "win32api.inc"
        #INCLUDE "gl.inc"
        #INCLUDE "GLU.INC"
        
        TYPE OglFlag_STRUCT
          EndProg     AS BIT * 1 IN BYTE
          MouseClk    AS BIT * 1
          OglBtnDead  AS BIT * 1
          RunGlDemo   AS BIT * 1
          TxtEntered  AS BIT * 1
        END TYPE
        
        TYPE Single2_STRUCT
          Mx  AS SINGLE
          My  AS SINGLE
        END TYPE
        
        TYPE Mouse_STRUCT
          Single2_STRUCT
        END TYPE
        
        MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                  '   correctly while in 2dimensional mode
        
        %GFX_WIN       =    5
        %BTN_END       =    6
        %BTN_OGL       =    7
        %TXBX_OGL_TXT  =    8
        
        %OGL_ERROR   = %WM_USER + 500
        
        GLOBAL tFlags AS OglFlag_STRUCT
        GLOBAL tMouse AS Mouse_STRUCT
        
        ' =======================================================================================
        ' All the setup goes here
        ' =======================================================================================
        
        SUB AssignFont(BYVAL GfxDc AS DWORD, FontHndl AS DWORD, FontName AS ASCIIZ)
        
        '======================================================
        ' This routine is the first step in creating text for
        ' OpenGl.  Scale the text with the height and width
        ' parameters.
        '======================================================
        
        FontHndl = CreateFont(-80, _                          ' Height of the font
                            0, _                              ' Width of the font
                            0, _                              ' Angle of escapement
                            0, _                              ' Orientation angle
                            %FW_BOLD, _                       ' Font weight
                            0, _                              ' Italic
                            0, _                              ' Underline
                            0, _                              ' Strikeout
                            %ANSI_CHARSET, _                  ' Character set identifier
                            %OUT_TT_PRECIS, _                 ' Output precision
                            %CLIP_DEFAULT_PRECIS, _           ' Clipping precision
                            %ANTIALIASED_QUALITY, _           ' Output quality
                            %FF_DONTCARE OR %DEFAULT_PITCH, _ ' Family and pitch
                            FontName$)                        ' Font name
        END SUB
        
        '-------------------------------------------------------------------------
        '-------------------------------------------------------------------------
        
        SUB RenderOglText(BYVAL X AS DWORD, BYVAL Y AS DWORD, BYVAL GfxDc AS DWORD, _
                          BYVAL FontBase AS DWORD, Txt AS STRING)
        
        '===============================================================
        ' This routine renders text at X and approximately Y.
        '
        ' Most of the code one sees uses the text string directly.  However,
        ' I could not make that work so I translated the text to a byte
        ' array instead.
        '
        ' A word about glListBase():
        ' In the OglBmpCharList routine I created 256 lists using glGenLists(256).
        ' Those lists were then filled using wglUseFontBitmaps(GfxDc, 0, 255, FontBase).
        ' If I had used 96 or 128 in glGenLists (glGenLists(96)) and in
        ' wglUseFontBitmaps used 32 for the starting character and 95 for the number of
        ' characters (wglUseFontBitmaps(GfxDc, 32, 95, FontBase)) I would have to
        ' subtract the starting character (32) from FontBase to produce the correct
        ' rendered characters.
        '===============================================================================
        
        LOCAL ChrList() AS BYTE
        
        glClear(%GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                 %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT)
        
        L = LEN(Txt$)
        
        DIM ChrList(0 TO L - 1)
        
        FOR I = 0 TO L - 1
          ChrList(I) = ASC(MID$(Txt$, I + 1, 1))
        NEXT I
        
        glColor3Ub(255, 255, 0)
        
        '=====================================================
        ' glTranslate does not work to position the text
        ' 40 is subtracted from the Y coordinate to
        ' compensate for the size of the text and put it at
        ' the approximate Y position
        
        glRasterPos2F(X, Y - 40)
        
        '=====================================================
        ' glPushAttrib(%GL_LIST_BIT)/glPopAttrib is used in most
        ' code I've seen.  However, I've seen no ill effects
        ' in this routine by not using those functions.
        ' They may be necessary if other types of lists are
        ' generated.
        '======================================================
        
        '======================================================
        ' If the starting character is not 0 subtract the
        ' starting character from FontBase.
        
        glListBase(FontBase)
        
        '======================================================
        
        glCallLists(L, %GL_UNSIGNED_BYTE, ChrList(0))
        
        SwapBuffers(GfxDc)
        
        END SUB
        
        '---------------------------------------------------------------
        '---------------------------------------------------------------
        
        FUNCTION PBMAIN ()
        LOCAL hDlg  AS DWORD
        
        LOCAL Txt AS STRING
        
        Txt$ = "Click on window to position text"
        
        DIALOG NEW 0, "Exploring Ogl - 3D Parallel Projection - Text", , , 201, 131, _
                                %WS_POPUP OR %WS_BORDER _
                                OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        
        CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                                %WS_CHILD OR _
                                                %WS_VISIBLE OR %SS_CENTER OR _
                                                %SS_NOPREFIX OR %SS_NOTIFY _
                                                OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
        
        CONTROL ADD TEXTBOX, hDlg, %TXBX_OGL_TXT, "", 5, 5, 190, 30
        
        CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
          OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
          %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
          %WS_EX_LTRREADING
        
        CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Submit Text", 120, 95, 75, 20, _
          %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
          OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
          %WS_EX_LTRREADING
        
        DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
        
        DIALOG SHOW MODAL hDlg, CALL Main_CB
        
        END FUNCTION
        
        '-------------------------------------------------------------
        '-------------------------------------------------------------
        
        CALLBACK FUNCTION Main_CB()
        
        LOCAL lParam AS LONG
        LOCAL wParam AS LONG
        
        LOCAL Hndl  AS DWORD
        
        LOCAL Txt AS STRING
        
        Hndl = CBHNDL
        
        SELECT CASE AS LONG CBMSG
        
          wParam = CBWPARAM
          CASE %WM_INITDIALOG
            CONTROL SHOW STATE Hndl, %GFX_WIN, %SW_HIDE
          CASE %WM_COMMAND
            wParam = CBCTLMSG
        
            SELECT CASE AS LONG wParam
              CASE %BN_CLICKED, %STN_CLICKED, 1
        
                SELECT CASE AS LONG CBCTL
                  CASE %GFX_WIN
                    tFlags.MouseClk = 1
                    CALL RunOgl(Hndl)
                    FUNCTION = 1
                    EXIT FUNCTION
        
                  CASE %BTN_END
                    tFlags.EndProg = 1
        '            CALL RunOgl(Hndl)
                    DIALOG END Hndl
                    FUNCTION = 1
                    EXIT FUNCTION
        
                  CASE %BTN_OGL
                    IF tFlags.TxtEntered = 0 THEN
                      CONTROL GET TEXT Hndl, %TXBX_OGL_TXT TO Txt$
                      IF Txt$ = "" THEN EXIT SELECT
                      CONTROL SHOW STATE Hndl, %TXBX_OGL_TXT, %SW_HIDE
                      CONTROL SHOW STATE Hndl, %GFX_WIN, %SW_SHOW
                      CONTROL SET TEXT Hndl, %BTN_OGL, "Run Ogl Demo"
                      tFlags.TxtEntered = 1
                      CALL RunOgl(Hndl, Txt$)
                      FUNCTION = 1
                      EXIT FUNCTION
                    END IF
        
                    tFlags.OglBtnDead = 1
                    tFlags.RunGlDemo = 1
                    CONTROL SET TEXT Hndl, %BTN_OGL, "DISABLED"
                    CONTROL DISABLE Hndl, %BTN_OGL
        '            CALL RunOgl(CBHNDL)
                    FUNCTION = 1
                    EXIT FUNCTION
        
                END SELECT
            END SELECT
        
          CASE %WM_DESTROY
            IF tFlags.EndProg THEN EXIT SELECT
            tFlags.EndProg = 1
        '    CALL RunOgl(Hndl)
        
          CASE %OGL_ERROR
            SELECT CASE wParam
              CASE 1
                MSGBOX "Could not find matching pixel format"
              CASE 2
                MSGBOX "Could not set selected pixel format"
              CASE 3
                MSGBOX "Could not create rendering context"
              CASE 4
                MSGBOX "Could not make rendering context current.  Defined window may not" _
                       + " support it"
            END SELECT
            DIALOG END Hndl
        END SELECT
        
        END FUNCTION
        
        '-----------------------------------------------------------
        '-----------------------------------------------------------
        
        SUB RunOgl(BYVAL Hndl AS DWORD, OPTIONAL Txt AS STRING)
        
        STATIC Wide  AS LONG
        STATIC High  AS LONG
        
        LOCAL X     AS LONG
        LOCAL Y     AS LONG
        LOCAL X1    AS LONG
        LOCAL Y1    AS LONG
        
        LOCAL FontHndl AS DWORD
        
        STATIC GfxDC        AS DWORD
        STATIC OglRc        AS DWORD
        STATIC GfxHndl      AS DWORD
        STATIC BmpFontBase  AS DWORD
        
        STATIC AryCnt       AS DWORD
        STATIC PntCnt       AS DWORD
        
        STATIC glLArray() AS DWORD
        STATIC glPArray() AS DWORD
        
        STATIC OglTxt AS STRING
        
        LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
        
        IF ISFALSE(GfxDc) THEN
          IF tFlags.EndProg THEN EXIT SUB
        
          CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
          CALL OglPixFormat(tPixFmt)
        
          OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
        
          IF OglRc = 0 THEN EXIT SUB
        
          CALL SetOglWindow(Wide, High)
        END IF
        
        IF tFlags.EndProg THEN
          CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
          IF BmpFontBase THEN glDeleteLists(BmpFontBase, 256)
          EXIT SUB
        END IF
        
        IF tFlags.TxtEntered THEN
          IF OglTxt$ <> "" THEN EXIT IF
          OglTxt$ = Txt$
          CALL AssignFont(GfxDc, FontHndl, "Comic Sans MS" + CHR$(0))
          CALL OglBmpCharList(GfxDc, FontHndl, BmpFontBase)
          EXIT SUB
        END IF
        
        IF tFlags.MouseClk THEN
          CALL Mouse(GfxHndl, Hndl)
                                         '=============================================
                                         ' Since the OpenGL graphics origin is at the lower left
          X  = tMouse.Mx                 ' corner of the drawing window, the mouse "y" coordinate
          Y  = High - tMouse.My          ' must be adjusted to produce the correct display
                                         ' location
                                         '=====================================================
          tFlags.MouseClk = 0
          CALL RenderOglText(X, Y, GfxDc, BmpFontBase, OglTxt$)
        END IF
        
        END SUB
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                            GfxDc AS DWORD, Wide AS LONG, High AS LONG)
        
        CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
        CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
        DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
        
        GfxDc = GetDc(GfxHndl)
        
        END SUB
        
        '-----------------------------------------------------------------
        '-----------------------------------------------------------------
        
        SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
        
        '==============================================================
        ' This is the 1st step in setting up windows for OpenGl support
        ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
        ' graphics
        '==============================================================
        
        pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
        pfd.nversion = 1
        pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
        pfd.dwlayermask = %PFD_MAIN_PLANE
        pfd.ipixeltype = %PFD_TYPE_RGBA
        pfd.ccolorbits = 24
        pfd.cdepthbits = 24
        pfd.caccumbits = 0
        pfd.cstencilbits = 0
        
        END SUB
        
        '---------------------------------------------------------------
        '---------------------------------------------------------------
        
        FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                            tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
        
        '================================================================
        '  This is the second step for OpenGL support
        '  ChoosePixelFormat selects a pixel format that matches that
        '  described in the PIXELFORMATDESCRIPTOR structure.
        '
        '  Each step is the setup is quried because not all windows support
        '  OpenGL rendering
        '================================================================
        
        LOCAL PixFormat AS DWORD
        LOCAL OglRc     AS DWORD
        
        LOCAL T AS LONG
        
        PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
        
        IF ISFALSE (PixFormat) THEN
          DIALOG POST Hndl, %OGL_ERROR, 1, 0
          EXIT FUNCTION
        END IF
        
        t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
        
        IF ISFALSE(t) THEN
          DIALOG POST Hndl, %OGL_ERROR, 2, 0
          EXIT FUNCTION
        END IF
        
        OglRc = wglCreateContext(GfxDc)
        
        IF ISFALSE(OglRc) THEN
          DIALOG POST Hndl, %OGL_ERROR, 3, 0
          EXIT FUNCTION
        END IF
        
        t = wglMakeCurrent(GfxDc, OglRc)
        
        IF ISFALSE(t) THEN
          DIALOG POST Hndl, %OGL_ERROR, 4, 0
          EXIT FUNCTION
        END IF
        
        SetOglPipe = OglRc
        END FUNCTION
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG)
        
        LOCAL ClearClr AS DWORD
        
        '=================================================================
        ' This defines the graphics environment.
        ' Getting this correct is crucial to using OpenGL.
        '
        ' gluOrtho2D is equivalent to using glOrtho with the FAR
        ' parameter set to -1 and the NEAR parameter set to 1
        '=================================================================
        
        ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                   %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
        
        glViewport(0, 0, Wide, High)
        glMatrixMode(%GL_PROJECTION)
        glLoadIdentity()
        glOrtho(0, Wide, 0, High, -100!, 300.000!)
        glMatrixMode(%GL_MODELVIEW)
        glClear(ClearClr)
        
        END SUB
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
        
        wglMakeCurrent(0, 0)
        wglDeleteContext(OglRc)
        ReleaseDc(GfxHndl, GfxDc)
        
        END SUB
        
        '-----------------------------------------------------------------
        '-----------------------------------------------------------------
        
        SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
        
        LOCAL tPoint AS POINT
        
        GetCursorPos(tPoint)
        ScreenToClient(GfxHndl, tPoint)
        
        tMouse.Mx = tPoint.X
        tMouse.My = tPoint.Y
        
        END SUB
        
        '------------------------------------------------------------------
        '------------------------------------------------------------------
        
        '----------------------------------------------------------------------
        '----------------------------------------------------------------------
        
        SUB OglBmpCharList(BYVAL GfxDc AS DWORD, BYVAL FontHndl AS DWORD, FontBase AS DWORD)
        
        '==========================================================
        ' This is the second step in creating text for OpenGl.
        '
        ' glGenLists(Number) creates Number empty display lists and
        ' returns the first display list "name", actually a number.
        '
        ' wglUseFontBitmaps(Device Context, Start Character, Number of
        '                   Characters, List Base)
        ' fills the empty lists with OpenGl instructions.
        '==========================================================
        
        LOCAL OldFont AS DWORD
        
        '==========================================================
        ' Create 256 lists, i. e., the number of characters in the
        ' Ascii character set. This need not be 256, it could be
        ' 128, 96, 64 or something else.
        '==========================================================
        
        FontBase = glGenLists(256)
        
        '==========================================================
        ' The reason I've added 100 to FontBase is to distinguish
        ' this list from other lists.
        '==========================================================
        
        FontBase = 100 + FontBase - 1
        
        OldFont = SelectObject(GfxDc, FontHndl)
        
        '==========================================================
        ' Starting with Ascii character zero fill 256 lists.
        '==========================================================
        
        wglUseFontBitmaps(GfxDc, 0, 255, FontBase)
        
        SelectObject(GfxDc, OldFont)
        DeleteObject(FontHndl)
        
        END SUB
        DDT code:

        Code:
        '=======================================================================
        '                            OPENGL FUNCTIONS USED
        '=======================================================================
        ' glViewport()
        ' glMatrixMode()
        ' glLoadIdentity
        ' glOrtho()
        ' glMatrixMode()
        ' glLoadIdentity
        ' glclear()
        ' glPushMatrix
        ' glTranslatef()
        ' glColor3Ub()
        ' glBegin()
        ' glEnd
        ' glVertex3F()
        ' glPopMatrix
        ' glFlush
        ' glLineWidth()
        ' glEnable()
        ' glHint()
        '=========================================================================
        '                            WINDOWS FUNCTIONS USED
        '=========================================================================
        ' GetDc
        ' ReleaseDc
        ' ChoosePixelFormat
        ' SetPixelFormat
        ' wglCreateContext
        ' wglMakeCurrent
        ' wglDeleteContext
        '=========================================================================
        '                          DDT FUNCTIONS USED
        '=========================================================================
        ' GRAPHICS BITMAP NEW
        ' GRAPHIC SCALE
        ' GRAPHIC GET PIXEL
        ' GRAPHIC TEXT SIZE
        ' GRAPHIC COLOR
        ' GRAPHIC PRINT
        '==========================================================================
        
        #COMPILE EXE
        #DEBUG DISPLAY ON
        DEFLNG A - Z
        
        #INCLUDE "WIN32API.INC"
        #INCLUDE "gl.inc"
        #INCLUDE "glu.inc"
        
        TYPE OglFlag_STRUCT
          EndProg     AS BIT * 1 IN BYTE
          MouseClk    AS BIT * 1
          OglBtnDead  AS BIT * 1
          RunGlDemo   AS BIT * 1
          TxtEntered  AS BIT * 1
        END TYPE
        
        TYPE Single2_STRUCT
          Mx  AS SINGLE
          My  AS SINGLE
        END TYPE
        
        TYPE Mouse_STRUCT
          Single2_STRUCT
        END TYPE
        
        
        MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                  '   correctly while in 2dimensional mode
        
        %GFX_WIN       =    5
        %BTN_END       =    6
        %BTN_OGL       =    7
        %TXBX_OGL_TXT  =    8
        
        %OGL_ERROR   = %WM_USER + 500
        
        GLOBAL tFlags AS OglFlag_STRUCT
        GLOBAL tMouse AS Mouse_STRUCT
        
        DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
        DECLARE SUB RunOgl(BYVAL Hndl AS DWORD, OPTIONAL Txt AS STRING)
        DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                    GfxDc AS DWORD, Wide AS LONG, High AS LONG)
        
        DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                BYVAL GfxHndl AS DWORD)
        
        DECLARE SUB OglRenderImage(glArray() AS DWORD, glPArray() AS DWORD, BYVAL GfxDc AS DWORD)
        
        DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
        
        DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                    tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
        
        
        DECLARE FUNCTION PBMAIN() AS LONG
        DECLARE CALLBACK FUNCTION Main_CB()
        
        FUNCTION PBMAIN()
        
        LOCAL hDlg  AS DWORD
        
        LOCAL Txt AS STRING
        
        Txt$ = "Click on window to position text"
        
        DIALOG NEW 0, "Exploring Ogl - 3D Parallel Projection - Text", , , 201, 131, _
                                %WS_POPUP OR %WS_BORDER _
                                OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        
        CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                                %WS_CHILD OR _
                                                %WS_VISIBLE OR %SS_CENTER OR _
                                                %SS_NOPREFIX OR %SS_NOTIFY _
                                                OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
        
        CONTROL ADD TEXTBOX, hDlg, %TXBX_OGL_TXT, "", 5, 5, 190, 30
        
        CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
          OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
          %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
          %WS_EX_LTRREADING
        
        CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Submit Text", 120, 95, 75, 20, _
          %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
          OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
          %WS_EX_LTRREADING
        
        DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
        
        DIALOG SHOW MODAL hDlg, CALL Main_CB
        
        END FUNCTION
        
        '------------------------------------------------------------
        '------------------------------------------------------------
        
        CALLBACK FUNCTION Main_CB()
        
        LOCAL lParam AS LONG
        LOCAL wParam AS LONG
        
        LOCAL Hndl  AS DWORD
        
        LOCAL Txt AS STRING
        
        Hndl = CBHNDL
        
        SELECT CASE AS LONG CBMSG
        
          wParam = CBWPARAM
          CASE %WM_INITDIALOG
            CONTROL SHOW STATE Hndl, %GFX_WIN, %SW_HIDE
          CASE %WM_COMMAND
            wParam = CBCTLMSG
        
            SELECT CASE AS LONG wParam
              CASE %BN_CLICKED, %STN_CLICKED, 1
        
                SELECT CASE AS LONG CBCTL
                  CASE %GFX_WIN
                    tFlags.MouseClk = 1
                    CALL RunOgl(Hndl)
                    FUNCTION = 1
                    EXIT FUNCTION
        
                  CASE %BTN_END
                    tFlags.EndProg = 1
                    CALL RunOgl(Hndl)
                    DIALOG END Hndl
                    FUNCTION = 1
                    EXIT FUNCTION
        
                  CASE %BTN_OGL
                    IF tFlags.TxtEntered = 0 THEN
                      CONTROL GET TEXT Hndl, %TXBX_OGL_TXT TO Txt$
                      IF Txt$ = "" THEN EXIT SELECT
                      CONTROL SHOW STATE Hndl, %TXBX_OGL_TXT, %SW_HIDE
                      CONTROL SHOW STATE Hndl, %GFX_WIN, %SW_SHOW
                      CONTROL SET TEXT Hndl, %BTN_OGL, "Disabled"
                      CONTROL DISABLE Hndl, %BTN_OGL
                      tFlags.TxtEntered = 1
                      tFlags.OglBtnDead = 1
                      CALL RunOgl(Hndl, Txt$)
                    END IF
        
                    FUNCTION = 1
                    EXIT FUNCTION
        
                END SELECT
            END SELECT
        
          CASE %WM_DESTROY
            IF tFlags.EndProg THEN EXIT SELECT
            tFlags.EndProg = 1
            CALL RunOgl(Hndl)
        
          CASE %OGL_ERROR
            SELECT CASE wParam
              CASE 1
                MSGBOX "Could not find matching pixel format"
              CASE 2
                MSGBOX "Could not set selected pixel format"
              CASE 3
                MSGBOX "Could not create rendering context"
              CASE 4
                MSGBOX "Could not make rendering context current.  Defined window may not" _
                       + " support it"
            END SELECT
            DIALOG END Hndl
        END SELECT
        
        END FUNCTION
        
        '------------------------------------------------------------
        '------------------------------------------------------------
        
        SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
        
        '==============================================================
        ' This is the 1st step in setting up windows for OpenGl support
        ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
        ' graphics
        '==============================================================
        
        pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
        pfd.nversion = 1
        pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
        pfd.dwlayermask = %PFD_MAIN_PLANE
        pfd.ipixeltype = %PFD_TYPE_RGBA
        pfd.ccolorbits = 24
        pfd.cdepthbits = 24
        pfd.caccumbits = 0
        pfd.cstencilbits = 0
        
        END SUB
        
        '---------------------------------------------------------------
        '---------------------------------------------------------------
        
        SUB RunOgl(BYVAL Hndl AS DWORD, OPTIONAL Txt AS STRING)
        
        STATIC Wide  AS LONG
        STATIC High  AS LONG
        
        LOCAL X     AS LONG
        LOCAL Y     AS LONG
        LOCAL X1    AS LONG
        LOCAL Y1    AS LONG
        
        STATIC GfxDC        AS DWORD
        STATIC OglRc        AS DWORD
        STATIC GfxHndl      AS DWORD
        
        STATIC AryCnt    AS DWORD
        STATIC PntCnt    AS DWORD
        
        STATIC glLArray() AS DWORD
        STATIC glPArray() AS DWORD
        
        STATIC OglTxt AS STRING
        
        LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
        
        IF ISFALSE(GfxDc) THEN
          IF tFlags.EndProg THEN EXIT SUB
        
          CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
          CALL OglPixFormat(tPixFmt)
        
          OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
        
          IF OglRc = 0 THEN EXIT SUB
        
          CALL SetOglWindow(Wide, High)
        END IF
        
        IF tFlags.EndProg THEN
          CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
          EXIT SUB
        END IF
        
        IF tFlags.TxtEntered THEN
          IF OglTxt$ <> "" THEN EXIT IF
          OglTxt$ = Txt$
        END IF
        
        IF tFlags.MouseClk THEN
          CALL Mouse(GfxHndl, Hndl)
                                         '=============================================
                                         ' Since the OpenGL graphics origin is at the lower left
          X  = tMouse.Mx                 ' corner of the drawing window, the mouse "y" coordinate
          Y  = High - tMouse.My          ' must be adjusted to produce the correct display
                                         ' location
                                         '=====================================================
          tFlags.MouseClk = 0
          CALL MakeOglText(X, Y, glPArray(), Wide, High, OglTxt$)
        END IF
        
        CALL OglRenderImage(glLArray(), glPArray(), GfxDc)
        
        END SUB
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                            tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
        
        '================================================================
        '  This is the second step for OpenGL support
        '  ChoosePixelFormat selects a pixel format that matches that
        '  described in the PIXELFORMATDESCRIPTOR structure.
        '
        '  Each step is the setup is quried because not all windows support
        '  OpenGL rendering
        '================================================================
        
        LOCAL PixFormat AS DWORD
        LOCAL OglRc     AS DWORD
        
        LOCAL T AS LONG
        
        PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
        
        IF ISFALSE (PixFormat) THEN
          DIALOG POST Hndl, %OGL_ERROR, 1, 0
          EXIT FUNCTION
        END IF
        
        t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
        
        IF ISFALSE(t) THEN
          DIALOG POST Hndl, %OGL_ERROR, 2, 0
          EXIT FUNCTION
        END IF
        
        OglRc = wglCreateContext(GfxDc)
        
        IF ISFALSE(OglRc) THEN
          DIALOG POST Hndl, %OGL_ERROR, 3, 0
          EXIT FUNCTION
        END IF
        
        t = wglMakeCurrent(GfxDc, OglRc)
        
        IF ISFALSE(t) THEN
          DIALOG POST Hndl, %OGL_ERROR, 4, 0
          EXIT FUNCTION
        END IF
        
        SetOglPipe = OglRc
        END FUNCTION
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG)
        
        LOCAL ClearClr AS DWORD
        
        '=================================================================
        ' This defines the graphics environment.
        ' Getting this correct is crucial to using OpenGL.
        '
        ' gluOrtho2D is equivalent to using glOrtho with the FAR
        ' parameter set to -1 and the NEAR parameter set to 1
        '=================================================================
        
        ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                   %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
        
        glViewport(0, 0, Wide, High)
        glMatrixMode(%GL_PROJECTION)
        glLoadIdentity()
        glOrtho(0, Wide, 0, High, -100!, 300.000!)
        glMatrixMode(%GL_MODELVIEW)
        glClear(ClearClr)
        
        
        END SUB
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
        
        wglMakeCurrent(0, 0)
        wglDeleteContext(OglRc)
        ReleaseDc(GfxHndl,GfxDc)
        
        END SUB
        
        '----------------------------------------------------------------
        '----------------------------------------------------------------
        
        SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                            GfxDc AS DWORD, Wide AS LONG, High AS LONG)
        
        CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
        CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
        DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
        
        GfxDc = GetDc(GfxHndl)
        
        END SUB
        
        '-----------------------------------------------------------------
        '-----------------------------------------------------------------
        
        SUB OglRenderImage(glArray() AS DWORD, glPArray() AS DWORD, BYVAL GfxDc AS DWORD)
        
        '==================================================================
        ' This draws the 2d picture.
        ' glClear must be used when tracking mouse clicks on the drawing window
        ' otherwise crazy images are produced.
        '
        ' The glPush/PopMatrix functions are used to reduce calculation errors
        ' when drawing the array.  Without those functions active
        ' errors begin to accumulate and the lines don't follow the mouse
        ' correctly.
        '
        ' glBegin() marks the beginning of the drwaing operation; glEnd marks
        ' the end of the drawing operation. With the %GL_LINES parameter, connected
        ' lines are drawn. With the %GL_LINE_LOOP parameter, connected lines are
        ' drawn and a line is drawn from the last point back to the first.
        '
        '==================================================================
        
        LOCAL ClearClr AS DWORD
        
        ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                   %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
        
        glPushMatrix
          glTranslateF(GL_FAC, GL_FAC, 0)
          glBegin(%GL_POINTS)
            glColor3Ub(255, 255, 0)
            FOR I = 1 TO UBOUND(glPArray, 2)
              glVertex3f(glPArray(1, I), glPArray(2, I), 0!)
            NEXT I
          glEnd
        glPopMatrix
        
        SwapBuffers(GfxDc)
        
        glClear(ClearClr)
        
        glFlush
        
        END SUB
        
        
        '------------------------------------------------------------------
        '------------------------------------------------------------------
        
        SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
        
        LOCAL tPoint AS POINT
        
        GetCursorPos(tPoint)
        ScreenToClient(GfxHndl, tPoint)
        
        tMouse.Mx = tPoint.X
        tMouse.My = tPoint.Y
        
        END SUB
        
        '-------------------------------------------------------------------
        '-------------------------------------------------------------------
        
        SUB MakeOglText(BYVAL X AS LONG, BYVAL Y AS LONG, PntAry() AS DWORD, BYVAL Wide AS LONG, _
                        BYVAL High AS LONG, Txt AS STRING)
        
        '=============================================================
        ' This routine makes a memory bitmap the size of the OpenGl window
        ' and scales it so the coordinates match those of OpenGl.
        ' It then scans the text to determine if the length of the
        ' text is longer than the window.  If the text is longer
        ' than the window it prints the portion shorter than the window,
        ' lops of the front portion, then determines if the remainder
        ' is longer than the window.
        '
        ' Finally it scans the memory bitmap for a specific color and
        ' stores the coordinates in the PntAry().
        '=============================================================
        
        LOCAL BmpHndl AS DWORD
        LOCAL Cntr    AS DWORD
        LOCAL Clr     AS DWORD
        LOCAL TxtWide AS DWORD
        LOCAL TxtHigh AS DWORD
        
        LOCAL TxtPart   AS STRING
        LOCAL TxtHolder AS STRING
        
        '==========================================
        ' Memory bitmap creation and scaling
        '==========================================
        
        GRAPHIC BITMAP NEW Wide, High TO BmpHndl
        GRAPHIC ATTACH BmpHndl, 0
        GRAPHIC SCALE (0, High) - (Wide, 0)
        GRAPHIC COLOR %RED, -2
        GRAPHIC TEXT SIZE Txt$ TO TxtWide, TxtHigh
        
        '===========================================
        ' Scan text and print to memory bitmap
        '===========================================
        
        IF X + TxtWide > Wide THEN
          TxtPart$ = Txt$
          TxtHolder = Txt$
          DO
            I = INSTR(-1, TxtPart$, " ")
            IF I THEN
              I = I - 1
              TxtPart$ = LEFT$(TxtPart$, I)
              GRAPHIC TEXT SIZE TxtPart$ TO TxtWide, TxtHigh
              IF X + TxtWide > Wide THEN
                ITERATE DO
              ELSE
        '        I = LEN(TxtPart$) + 1
        '        TxtHolder$ = MID$(Txt$, I)
                GRAPHIC SET POS (X, Y)
                GRAPHIC PRINT TxtPart$
                TxtHolder$ = REMAIN$(TxtHolder$, TxtPart$)
                GRAPHIC TEXT SIZE TxtHolder$ TO TxtWide, TxtHigh
                IF X + TxtWide > Wide THEN
                  Y = Y - TxtHigh - TxtHigh * .25
                  TxtPart$ = TxtHolder$
                  ITERATE DO
                END IF
                EXIT DO
              END IF
            END IF
          LOOP
        END IF
        
        GRAPHIC SET POS (X, Y)
        
        IF TxtHolder$ <> "" THEN
          Y = Y - TxtHigh - TxtHigh * .25
          GRAPHIC SET POS(X, Y)
          GRAPHIC PRINT TxtHolder$
        ELSE
          GRAPHIC PRINT Txt$
        END IF
        
        '=========================================
        ' Scan memory bitmap for color and store
        ' coordinates in array
        '=========================================
        
        REDIM PntAry(1 TO 2, 1 TO 1)
        Cntr = 0
        
        FOR I = 0 TO High - 1
          FOR J = O TO Wide - 1
            GRAPHIC GET PIXEL (J, I) TO Clr
            IF Clr = %RED THEN
              INCR Cntr
              REDIM PRESERVE PntAry(1 TO 2, 1 TO Cntr)
              PntAry(1, Cntr) = J
              PntAry(2, Cntr) = I
            END IF
          NEXT J
        NEXT I
        
        GRAPHIC BITMAP END
        
        END SUB
        Walt Decker

        Comment


        • #5
          Points and Lines Revisited

          The following code introduces a new ortho projection matrix and a way to translate window coordinates into OpenGL projection coordinates. It also demonstrates the effect of glRotateF() on points and lines. Bear in mind that the effects demonstrated can be accomplished on a 2D surface simply by moving the origin.

          The code is fairly well commented.

          Code:
          '=======================================================================
          '                            OPENGL FUNCTIONS USED
          '=======================================================================
          ' glViewport()
          ' glMatrixMode()
          ' glLoadIdentity
          ' glOrtho()
          ' glclear()
          ' glPushMatrix
          ' glTranslatef()
          ' glColor3Ub()
          ' glBegin()
          ' glEnd
          ' glVertex3F()
          ' glRotateF()
          ' glGet...()
          ' glPointSize()
          ' glPopMatrix
          ' glFlush
          ' glFinish
          ' gluUnProject()
          '=========================================================================
          '                            WINDOWS FUNCTIONS USED
          '=========================================================================
          ' GetDc
          ' ReleaseDc
          ' ChoosePixelFormat
          ' SetPixelFormat
          ' wglCreateContext
          ' wglMakeCurrent
          ' wglDeleteContext
          '=========================================================================
          
          #COMPILE EXE
          
          DEFLNG A - Z
          
          #INCLUDE "WIN32API.INC"
          #INCLUDE "gl.inc"
          #INCLUDE "glu.inc"
          
          TYPE OglFlag_STRUCT
            EndProg     AS BIT * 1 IN BYTE
            MouseClk    AS BIT * 1
            OglBtnDead  AS BIT * 1
            RunGlDemo   AS BIT * 1
          END TYPE
          
          TYPE Single2_STRUCT
            Mx  AS SINGLE
            My  AS SINGLE
          END TYPE
          
          TYPE Mouse_STRUCT
            Single2_STRUCT
          END TYPE
          
          
          MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                    '   correctly while in 2dimensional mode
          
          %GFX_WIN     =    5
          %BTN_END     =    6
          %BTN_OGL     =    7
          
          
          %OGL_ERROR   = %WM_USER + 500
          
          GLOBAL tFlags AS OglFlag_STRUCT
          GLOBAL tMouse AS Mouse_STRUCT
          
          DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
          DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
          DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                      GfxDc AS DWORD, Wide AS LONG, High AS LONG)
          
          DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                  BYVAL GfxHndl AS DWORD)
          
          DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
          
          DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
          
          
          DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                      tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
          
          
          DECLARE FUNCTION PBMAIN() AS LONG
          DECLARE CALLBACK FUNCTION Main_CB()
          
          FUNCTION PBMAIN()
          
          LOCAL hDlg  AS DWORD
          
          LOCAL Txt AS STRING
          
          Txt$ = "Click mouse on window to select location"
          
          DIALOG NEW 0, "Exploring Ogl - Ortho Projection - Points & Lines", , , 201, 131, _
                                  %WS_POPUP OR %WS_BORDER _
                                  OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                  %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                  %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                  %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
          
          CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                                  %WS_CHILD OR _
                                                  %WS_VISIBLE OR %SS_CENTER OR _
                                                  %SS_NOPREFIX OR %SS_NOTIFY _
                                                  OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
          
          CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
            OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
            %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
            %WS_EX_LTRREADING
          
          CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
            %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
            OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
            %WS_EX_LTRREADING
          
          DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
          
          DIALOG SHOW MODAL hDlg, CALL Main_CB
          
          END FUNCTION
          
          '------------------------------------------------------------
          '------------------------------------------------------------
          
          CALLBACK FUNCTION Main_CB()
          
          LOCAL lParam AS LONG
          LOCAL wParam AS LONG
          
          SELECT CASE AS LONG CBMSG
          
            wParam = CBWPARAM
            CASE %WM_INITDIALOG
          
            CASE %WM_COMMAND
              wParam = CBCTLMSG
              SELECT CASE AS LONG wParam
                CASE %BN_CLICKED, %STN_CLICKED, 1
                  SELECT CASE AS LONG CBCTL
                    CASE %GFX_WIN
                      tFlags.MouseClk = 1
                      CALL RunOgl(CBHNDL)
                      FUNCTION = 1
                      EXIT FUNCTION
          
                    CASE %BTN_END
                      tFlags.EndProg = 1
                      CALL RunOgl(CBHNDL)
                      DIALOG END CBHNDL
                      FUNCTION = 1
                      EXIT FUNCTION
          
                    CASE %BTN_OGL
                      CONTROL DISABLE CBHNDL, %BTN_OGL
                      tFlags.OglBtnDead = 1
                      tFlags.RunGlDemo = 1
                      CALL RunOgl(CBHNDL)
                      FUNCTION = 1
                      EXIT FUNCTION
          
                  END SELECT
              END SELECT
          
            CASE %WM_DESTROY
              IF tFlags.EndProg THEN EXIT SELECT
              tFlags.EndProg = 1
              CALL RunOgl(CBHNDL)
          
            CASE %OGL_ERROR
              SELECT CASE wParam
                CASE 1
                  MSGBOX "Could not find matching pixel format"
                CASE 2
                  MSGBOX "Could not set selected pixel format"
                CASE 3
                  MSGBOX "Could not create rendering context"
                CASE 4
                  MSGBOX "Could not make rendering context current.  Defined window may not" _
                         + " support it"
              END SELECT
              DIALOG END CBHNDL
          END SELECT
          
          END FUNCTION
          
          '------------------------------------------------------------
          '------------------------------------------------------------
          
          SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
          
          '==============================================================
          ' This is the 1st step in setting up windows for OpenGl support
          ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
          ' graphics
          '==============================================================
          
          pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
          pfd.nversion = 1
          pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
          pfd.dwlayermask = %PFD_MAIN_PLANE
          pfd.ipixeltype = %PFD_TYPE_RGBA
          pfd.ccolorbits = 24
          pfd.cdepthbits = 24
          pfd.caccumbits = 0
          pfd.cstencilbits = 0
          
          END SUB
          
          '---------------------------------------------------------------
          '---------------------------------------------------------------
          
          SUB RunOgl(BYVAL Hndl AS DWORD)
          
          STATIC Wide  AS LONG
          STATIC High  AS LONG
          
          STATIC GfxDC     AS DWORD
          STATIC OglRc     AS DWORD
          STATIC GfxHndl   AS DWORD
          
          LOCAL X     AS DOUBLE
          LOCAL Y     AS DOUBLE
          LOCAL Z     AS DOUBLE
          
          LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
          
          IF ISFALSE(GfxDc) THEN
            IF tFlags.EndProg THEN EXIT SUB
          
            CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
            CALL OglPixFormat(tPixFmt)
          
            OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
          
            IF OglRc = 0 THEN EXIT SUB
          
            CALL SetOglWindow(Wide, High, 100)
          
          END IF
          
          IF tFlags.EndProg THEN
            CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
            EXIT SUB
          END IF
          
          IF tFlags.MouseClk THEN
            CALL Mouse(GfxHndl, 0)
            X = tMouse.Mx
                                    '==========================================
                                    ' Since windows places 0,0 at the upper
            Y = High - tMouse.My    ' left corner of the display and Ogl locates
                                    ' 0,0 at the lower left corner the Y coordinate
                                    ' must be adjusted.
                                    '==========================================
          
            CALL WindowToProjection(X, Y, Z)  '<---- See SUB WindowToProjection
          
            IF tFlags.RunGlDemo THEN EXIT IF
          
            '=========== We don't pass the value of Z because it will be reset ==========
          
            CALL OglRenderImage(X, Y, GfxDc)
          
            tFlags.MouseClk = 0
            EXIT SUB
          END IF
          
          IF tFlags.RunGlDemo THEN
            IF tFlags.MouseClk = 0 THEN
              MSGBOX "Click mouse in window to select location"
              EXIT SUB
            END IF
            CALL glRunDemo(X, Y, GfxDc)
            tFlags.MouseClk = 0
          END IF
          END SUB
          
          '----------------------------------------------------------------
          '----------------------------------------------------------------
          
          FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                              tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
          
          '================================================================
          '  This is the second step for OpenGL support
          '  ChoosePixelFormat selects a pixel format that matches that
          '  described in the PIXELFORMATDESCRIPTOR structure.
          '
          '  Each step in the setup is quried because not all windows support
          '  OpenGL rendering
          '================================================================
          
          LOCAL PixFormat AS DWORD
          LOCAL OglRc     AS DWORD
          
          LOCAL T AS LONG
          
          PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
          
          IF ISFALSE (PixFormat) THEN
            DIALOG POST Hndl, %OGL_ERROR, 1, 0
            EXIT FUNCTION
          END IF
          
          t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
          
          IF ISFALSE(t) THEN
            DIALOG POST Hndl, %OGL_ERROR, 2, 0
            EXIT FUNCTION
          END IF
          
          OglRc = wglCreateContext(GfxDc)
          
          IF ISFALSE(OglRc) THEN
            DIALOG POST Hndl, %OGL_ERROR, 3, 0
            EXIT FUNCTION
          END IF
          
          t = wglMakeCurrent(GfxDc, OglRc)
          
          IF ISFALSE(t) THEN
            DIALOG POST Hndl, %OGL_ERROR, 4, 0
            EXIT FUNCTION
          END IF
          
          SetOglPipe = OglRc
          END FUNCTION
          
          '----------------------------------------------------------------
          '----------------------------------------------------------------
          
          SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                           BYVAL OrthoRange AS LONG)
          
          LOCAL ClearClr AS DWORD
          
          LOCAL Aspect AS SINGLE
          LOCAL Xmin   AS SINGLE
          LOCAL Ymin   AS SINGLE
          LOCAL Xmax   AS SINGLE
          LOCAL Ymax   AS SINGLE
          LOCAL Zmin   AS SINGLE
          LOCAL Zmax   AS SINGLE
          
          '=================================================================
          ' This defines the graphics environment.
          ' Getting this correct is crucial to using OpenGL.
          '
          ' In previous examples the orthographic projection was set to the
          ' window coordinates.  This now changes the projection coordinates
          ' to something other than the window coordinates.
          '=================================================================
          
          ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                     %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
          
          IF Wide <= High THEN
            Aspect! = High / Wide
          ELSE
            Aspect! = Wide / High
          END IF
          
          IF Wide <= High THEN
            Xmin! = -OrthoRange / 2
            Xmax! = OrthoRange  / 2
            Ymin! = (-OrthoRange / 2) * Aspect!
            Ymax! = (OrthoRange / 2) * Aspect!
          ELSE
            Xmin! = (-OrthoRange / 2) * Aspect!
            Xmax! = (OrthoRange / 2) * Aspect!
            Ymin! = (-OrthoRange / 2)
            Ymax! = (OrthoRange  / 2)
          END IF
          
          Zmin! = -OrthoRange / 2
          Zmax! = OrthoRange
          
          glViewport(0, 0, Wide, High)
          glMatrixMode(%GL_PROJECTION)
          glLoadIdentity
          glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
          glMatrixMode(%GL_MODELVIEW)
          glLoadIdentity
          glClear(ClearClr)
          
          END SUB
          
          
          '----------------------------------------------------------------
          '----------------------------------------------------------------
          
          SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
          
          wglMakeCurrent(0, 0)
          wglDeleteContext(OglRc)
          ReleaseDc(GfxHndl,GfxDc)
          
          END SUB
          
          '----------------------------------------------------------------
          '----------------------------------------------------------------
          
          SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                              GfxDc AS DWORD, Wide AS LONG, High AS LONG)
          
          CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
          CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
          DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
          
          GfxDc = GetDc(GfxHndl)
          
          END SUB
          
          '-----------------------------------------------------------------
          '-----------------------------------------------------------------
          
          SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
          
          '=============================================================
          ' This routine draws a coil of dots on the screen.
          ' To start, X and Y are the origin of the first group of dots.
          ' As Z increases the dots move up the screen to produce the
          ' coil.
          '=============================================================
          
          LOCAL ClearClr AS DWORD
          
          LOCAL Xc    AS SINGLE
          LOCAL Yc    AS SINGLE
          LOCAL Pi    AS SINGLE
          LOCAL Angle AS SINGLE
          LOCAL Z     AS SINGLE
          
          Pi! = 4 * ATN(1)  '<--- Number or radians in 1/2 circle
          
          ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                     %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
          
          Xc = X
          Yc = Y
          
          '==========================================================
          ' In the FOR/NEXT loop below you see:
          '
          '     X = Xc + 30 * SIN(Angle!)
          '     Y = Yc + 20 * COS(Angle!)
          '
          ' If glTranslateF(Xc, Yc, 0) is used the above can be
          ' reduced to:
          '
          '      X = 30 * SIN(Angle!)
          '      Y = 20 * COS(Angle!)
          '
          '==========================================================
          
          glPushMatrix
          
          '==========================================================
          ' The parameter list of glRotate(Angle in degrees, X, Y, Z)
          '==========================================================
          
          glRotateF(-20, 1, 0, 0)
          glRotateF(10, 0, 1, 0)
          
          Z = -100
          glColor3Ub(200, 255, 200)
          glBegin(%GL_POINTS)
          
            FOR Angle! = 0.0 TO 2.0 * Pi! * 6.0 STEP 0.15
              X = Xc + 30 * SIN(Angle!)
              Y = Yc + 20 * COS(Angle!)
              glVertex3F(X, Y, Z)
              Z = Z + .5
            NEXT Angle!
          
          glEnd
          glPopMatrix
          SwapBuffers(GfxDc)
          glClear(ClearClr)
          
          glFlush
          
          END SUB
          
          '------------------------------------------------------------------
          '------------------------------------------------------------------
          
          SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
          
          LOCAL tPoint AS POINT
          
          GetCursorPos(tPoint)
          ScreenToClient(GfxHndl, tPoint)
          
          tMouse.Mx = tPoint.X
          tMouse.My = tPoint.Y
          
          END SUB
          
          '-------------------------------------------------------------------
          '-------------------------------------------------------------------
          
          SUB glRunDemo(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
          
          '==============================================================
          ' This demo is basically the SUB glRenderImage() code but it
          ' introduces glGet...() and glPointsize().
          '
          ' glGet...() enables the programmer to retrieve virtually all the
          ' OpenGL state variables.  Many of those variables can be changed
          ' via a function aimed specifically at the variable.
          '
          ' Here we use glGet...() to retrieve the supported pixel size ranges
          ' and sizes.  Then we use glPointSize() to incrementally change the
          ' pixel size.
          '
          ' The second part of the code simply connects the dots using
          ' %GL_LINE_STRIP in glBegin() instead of %GL_POINTS.
          '===================================================================
          
          LOCAL Xc            AS SINGLE
          LOCAL Yc            AS SINGLE
          LOCAL Pi            AS SINGLE
          LOCAL Angle         AS SINGLE
          LOCAL Z             AS SINGLE
          LOCAL StepSize      AS SINGLE
          LOCAL CurSize       AS SINGLE
          
          LOCAL PointSizes()  AS SINGLE
          
          DIM PointSizes(1)   '<---- glGet...() requires an array of 2 elements
          
                            '======== Get the values =============
          
          glGetFloatV(%GL_POINT_SIZE_RANGE, PointSizes(0))
          glGetFloatV(%GL_POINT_SIZE_GRANULARITY, StepSize)
          
          CurSize = PointSizes(0)  '<---- Store the current pixel size
          
          Pi! = 4 * ATN(1)
          
          ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                     %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
          
          Xc = X
          Yc = Y
          
          glPushMatrix
          
          glTranslateF(Xc, Yc, 0)
          glRotateF(-20, 1, 0, 0)
          glRotateF(10, 0, 1, 0)
          
          Z = -100
          
          glColor3Ub(200, 255, 200)
            FOR Angle! = 0.0 TO 2.0 * Pi! * 3.0 STEP 0.15
          
              glPointSize(CurSize)
          
              X = 30 * SIN(Angle!)
              Y = 20 * COS(Angle!)
          
              glBegin(%GL_POINTS)
                glVertex3F(X, Y, Z)
              glEnd
          
              Z = Z + .5
          
              IF Angle! >= Pi THEN     '<---- Set the new pixel size
                CurSize = CurSize + StepSize
              END IF
          
            NEXT Angle!
          
          glPopMatrix
          SwapBuffers(GfxDc)
          glClear(ClearClr)
          glFinish
          
          glPointSize(PointSizes(0)) '<---- Set pixel size back to the smallest
          
          '====================== END OF 1st HALF =======================
          
          SLEEP 1000
          
          
          Angle! = 0
          X = Xc
          Y = Yc
          
          glPushMatrix
          
          glTranslateF(Xc, Yc, 0)
          glRotateF(-20, 1, 0, 0)
          glRotateF(20, 0, 1, 0)
          
          glRotateF(-20, 1, 0, 0)
          glRotateF(10, 0, 1, 0)
          
          Z = -100
          glColor3Ub(200, 200, 255)
          glBegin(%GL_LINE_STRIP)
          
            FOR Angle! = 0.0 TO 2.0 * Pi! * 6.0 STEP 0.15
              X = 30 * SIN(Angle!)
              Y = 20 * COS(Angle!)
              glVertex3F(X, Y, Z)
              Z = Z + .5
            NEXT Angle!
          
          glEnd
          glPopMatrix
          SwapBuffers(GfxDc)
          glClear(ClearClr)
          
          glFlush
          glFinish
          
          END SUB
          
          '------------------------------------------------------------------
          '------------------------------------------------------------------
          
          SUB WindowToProjection(X AS DOUBLE, Y AS DOUBLE, Z AS DOUBLE)
          
          '============================================================
          ' Since the orthographic coordinate system does not reflect
          ' the window coordinate system, the window coordinate system
          ' is translated to the ortho system by gluUnProject().
          '
          ' That OpenGL function uses the window values and the values
          ' stored in the viewport matrix, the modle matrix and the
          ' projection matrix to calculate the ortho coordinates.  This
          ' routine can also be used to calculate the perspective view
          ' coordinates.
          '
          ' Because OpenGL uses the various matricies for it's calculations
          ' we have to get those matricies before calling gluUnProject().
          ' That's what the various forms of glGet...() does.  Along with
          ' our window coordinates we pass those matricies to gluUnProject()
          ' and it returns the OGL coordinates in the last three parameters:
          ' WinX, WinY, WinZ.
          '============================================================
          
          LOCAL WinViewport()   AS LONG
          LOCAL ModleMatrix()   AS DOUBLE
          LOCAL ProjectMatrix() AS DOUBLE
          
          LOCAL WinX AS DOUBLE
          LOCAL WinY AS DOUBLE
          LOCAL WinZ AS DOUBLE
          
          DIM WinViewPort(0 TO 1, 0 TO 1)    '<--- 4 element array
          DIM ModleMatrix(0 TO 3, 0 TO 3)    '<--- 16 element array
          DIM ProjectMatrix(0 TO 3, 0 TO 3)
          
          glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
          glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
          glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
          
          gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
          
          X = WinX
          Y = WinY
          Z = WinZ
          
          END SUB
          Walt Decker

          Comment


          • #6
            Stipple Anyone?

            Want a line pattern or a polygon pattern? Stippling may be the answer.

            OpenGL uses a WORD pattern to perform line stippling and a BYTE matrix to perform polygon stippling. The line pattern is read from most significant bit to least significant bit. The repeat factor and pattern is set in the glLineStipple() function and can be changed at any time.

            When creating the matrix for polygon stippling the data should be entered from the bottom to the top of the pattern. MS states that the matrix should be 32 X 32; however, I didn't use that size and the polygon was still stippled.

            There are not many comment in this code. It's pretty self-explanatory.

            {Edit} :

            I forgot to mention that the stipple pattern on a polygon will not rotate if the polygon is rotated. To get the pattern to rotate with the polygon texture mapping must be used. Texture mapping will be discussed in a future post.

            Code:
            '=======================================================================
            '                            OPENGL FUNCTIONS USED
            '=======================================================================
            ' glViewport()
            ' glMatrixMode()
            ' glLoadIdentity
            ' glOrtho()
            ' glclear()
            ' glPushMatrix
            ' glTranslatef()
            ' glColor3Ub()
            ' glBegin()
            ' glEnd
            ' glVertex3F()
            ' glPopMatrix
            ' glEnable()
            ' glDisable()
            ' glLineStipple()
            ' glPolygonStipple()
            ' glFlush
            ' glFinish
            '=========================================================================
            '                            WINDOWS FUNCTIONS USED
            '=========================================================================
            ' GetDc
            ' ReleaseDc
            ' ChoosePixelFormat
            ' SetPixelFormat
            ' wglCreateContext
            ' wglMakeCurrent
            ' wglDeleteContext
            '=========================================================================
            
            #COMPILE EXE
            
            DEFLNG A - Z
            
            #INCLUDE "WIN32API.INC"
            #INCLUDE "gl.inc"
            #INCLUDE "glu.inc"
            
            TYPE OglFlag_STRUCT
              EndProg     AS BIT * 1 IN BYTE
              MouseClk    AS BIT * 1
              OglBtnDead  AS BIT * 1
              RunGlDemo   AS BIT * 1
            END TYPE
            
            TYPE Single2_STRUCT
              Mx  AS SINGLE
              My  AS SINGLE
            END TYPE
            
            TYPE Mouse_STRUCT
              Single2_STRUCT
            END TYPE
            
            
            MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                      '   correctly while in 2dimensional mode
            
            %GFX_WIN     =    5
            %BTN_END     =    6
            %BTN_OGL     =    7
            
            
            %OGL_ERROR   = %WM_USER + 500
            
            GLOBAL tFlags AS OglFlag_STRUCT
            GLOBAL tMouse AS Mouse_STRUCT
            
            DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
            DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
            DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                        GfxDc AS DWORD, Wide AS LONG, High AS LONG)
            
            DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                    BYVAL GfxHndl AS DWORD)
            
            DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
            
            DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
            
            
            DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                        tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
            
            
            DECLARE FUNCTION PBMAIN() AS LONG
            DECLARE CALLBACK FUNCTION Main_CB()
            
            FUNCTION PBMAIN()
            
            LOCAL hDlg  AS DWORD
            
            LOCAL Txt AS STRING
            
            Txt$ = "Click mouse on window to see line stippeling" + $CRLF + _
                   "Click button 'Run Ogl Demo' to see polygon stippeling"
            
            DIALOG NEW 0, "Exploring Ogl - Ortho Projection - Stippeling", , , 201, 131, _
                                    %WS_POPUP OR %WS_BORDER _
                                    OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                    %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                    %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                    %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
            
            CONTROL ADD LABEL,  hDlg, %GFX_WIN, Txt$, 5, 5, 190, 80, _
                                                    %WS_CHILD OR _
                                                    %WS_VISIBLE OR %SS_CENTER OR _
                                                    %SS_NOPREFIX OR %SS_NOTIFY _
                                                    OR %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
            
            CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
              OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
              %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
              %WS_EX_LTRREADING
            
            CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
              OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
              %WS_EX_LTRREADING
            
            DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
            
            DIALOG SHOW MODAL hDlg, CALL Main_CB
            
            END FUNCTION
            
            '------------------------------------------------------------
            '------------------------------------------------------------
            
            CALLBACK FUNCTION Main_CB()
            
            LOCAL lParam AS LONG
            LOCAL wParam AS LONG
            
            SELECT CASE AS LONG CBMSG
            
              wParam = CBWPARAM
              CASE %WM_INITDIALOG
            
              CASE %WM_COMMAND
                wParam = CBCTLMSG
                SELECT CASE AS LONG wParam
                  CASE %BN_CLICKED, %STN_CLICKED, 1
                    SELECT CASE AS LONG CBCTL
                      CASE %GFX_WIN
                        IF Tflags.RunGlDemo THEN EXIT SELECT
                        tFlags.MouseClk = 1
                        CALL RunOgl(CBHNDL)
                        FUNCTION = 1
                        EXIT FUNCTION
            
                      CASE %BTN_END
                        tFlags.EndProg = 1
                        CALL RunOgl(CBHNDL)
                        DIALOG END CBHNDL
                        FUNCTION = 1
                        EXIT FUNCTION
            
                      CASE %BTN_OGL
                        CONTROL DISABLE CBHNDL, %BTN_OGL
                        tFlags.OglBtnDead = 1
                        tFlags.RunGlDemo = 1
                        CALL RunOgl(CBHNDL)
                        FUNCTION = 1
                        EXIT FUNCTION
            
                    END SELECT
                END SELECT
            
              CASE %WM_DESTROY
                IF tFlags.EndProg THEN EXIT SELECT
                tFlags.EndProg = 1
                CALL RunOgl(CBHNDL)
            
              CASE %OGL_ERROR
                SELECT CASE wParam
                  CASE 1
                    MSGBOX "Could not find matching pixel format"
                  CASE 2
                    MSGBOX "Could not set selected pixel format"
                  CASE 3
                    MSGBOX "Could not create rendering context"
                  CASE 4
                    MSGBOX "Could not make rendering context current.  Defined window may not" _
                           + " support it"
                END SELECT
                DIALOG END CBHNDL
            END SELECT
            
            END FUNCTION
            
            '------------------------------------------------------------
            '------------------------------------------------------------
            
            SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
            
            '==============================================================
            ' This is the 1st step in setting up windows for OpenGl support
            ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
            ' graphics
            '==============================================================
            
            pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
            pfd.nversion = 1
            pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
            pfd.dwlayermask = %PFD_MAIN_PLANE
            pfd.ipixeltype = %PFD_TYPE_RGBA
            pfd.ccolorbits = 24
            pfd.cdepthbits = 24
            pfd.caccumbits = 0
            pfd.cstencilbits = 0
            
            END SUB
            
            '---------------------------------------------------------------
            '---------------------------------------------------------------
            
            SUB RunOgl(BYVAL Hndl AS DWORD)
            
            STATIC Wide  AS LONG
            STATIC High  AS LONG
            
            STATIC GfxDC     AS DWORD
            STATIC OglRc     AS DWORD
            STATIC GfxHndl   AS DWORD
            
            LOCAL Img() AS BYTE
            
            LOCAL X     AS DOUBLE
            LOCAL Y     AS DOUBLE
            LOCAL Z     AS DOUBLE
            
            LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
            
            IF ISFALSE(GfxDc) THEN
              IF tFlags.EndProg THEN EXIT SUB
            
              CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
              CALL OglPixFormat(tPixFmt)
            
              OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
            
              IF OglRc = 0 THEN EXIT SUB
            
              CALL SetOglWindow(Wide, High, 100)
            
            END IF
            
            IF tFlags.EndProg THEN
              CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
              EXIT SUB
            END IF
            
            IF tFlags.MouseClk THEN
              CALL Mouse(GfxHndl, 0)
              X = tMouse.Mx
                                      '==========================================
                                      ' Since windows places 0,0 at the upper
              Y = High - tMouse.My    ' left corner of the display and Ogl locates
                                      ' 0,0 at the lower left corner the Y coordinate
                                      ' must be adjusted.
                                      '==========================================
              CALL OglRenderImage(X, Y, GfxDc)
            
              tFlags.MouseClk = 0
              EXIT SUB
            END IF
            
            IF tFlags.RunGlDemo THEN
              DIM Img(1)
              CALL StippleData(Img())
              CALL glRunDemo(Img(), GfxDc)
            END IF
            END SUB
            
            '----------------------------------------------------------------
            '----------------------------------------------------------------
            
            FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
            
            '================================================================
            '  This is the second step for OpenGL support
            '  ChoosePixelFormat selects a pixel format that matches that
            '  described in the PIXELFORMATDESCRIPTOR structure.
            '
            '  Each step in the setup is quried because not all windows support
            '  OpenGL rendering
            '================================================================
            
            LOCAL PixFormat AS DWORD
            LOCAL OglRc     AS DWORD
            
            LOCAL T AS LONG
            
            PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
            
            IF ISFALSE (PixFormat) THEN
              DIALOG POST Hndl, %OGL_ERROR, 1, 0
              EXIT FUNCTION
            END IF
            
            t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
            
            IF ISFALSE(t) THEN
              DIALOG POST Hndl, %OGL_ERROR, 2, 0
              EXIT FUNCTION
            END IF
            
            OglRc = wglCreateContext(GfxDc)
            
            IF ISFALSE(OglRc) THEN
              DIALOG POST Hndl, %OGL_ERROR, 3, 0
              EXIT FUNCTION
            END IF
            
            t = wglMakeCurrent(GfxDc, OglRc)
            
            IF ISFALSE(t) THEN
              DIALOG POST Hndl, %OGL_ERROR, 4, 0
              EXIT FUNCTION
            END IF
            
            SetOglPipe = OglRc
            END FUNCTION
            
            '----------------------------------------------------------------
            '----------------------------------------------------------------
            
            SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                             BYVAL OrthoRange AS LONG)
            
            LOCAL ClearClr AS DWORD
            
            LOCAL Aspect AS SINGLE
            LOCAL Xmin   AS SINGLE
            LOCAL Ymin   AS SINGLE
            LOCAL Xmax   AS SINGLE
            LOCAL Ymax   AS SINGLE
            LOCAL Zmin   AS SINGLE
            LOCAL Zmax   AS SINGLE
            
            '=================================================================
            ' This defines the graphics environment.
            ' Getting this correct is crucial to using OpenGL.
            '
            ' In previous examples the orthographic projection was set to the
            ' window coordinates.  This now changes the projection coordinates
            ' to something other than the window coordinates.
            '=================================================================
            
            ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                       %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
            
            IF Wide <= High THEN
              Aspect! = High / Wide
            ELSE
              Aspect! = Wide / High
            END IF
            
            IF Wide <= High THEN
              Xmin! = -OrthoRange / 2
              Xmax! = OrthoRange  / 2
              Ymin! = (-OrthoRange / 2) * Aspect!
              Ymax! = (OrthoRange / 2) * Aspect!
            ELSE
              Xmin! = (-OrthoRange / 2) * Aspect!
              Xmax! = (OrthoRange / 2) * Aspect!
              Ymin! = (-OrthoRange / 2)
              Ymax! = (OrthoRange  / 2)
            END IF
            
            Zmin! = -OrthoRange / 2
            Zmax! = OrthoRange
            
            glViewport(0, 0, Wide, High)
            glMatrixMode(%GL_PROJECTION)
            glLoadIdentity
            glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
            glMatrixMode(%GL_MODELVIEW)
            glLoadIdentity
            glClear(ClearClr)
            
            END SUB
            
            
            '----------------------------------------------------------------
            '----------------------------------------------------------------
            
            SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
            
            wglMakeCurrent(0, 0)
            wglDeleteContext(OglRc)
            ReleaseDc(GfxHndl,GfxDc)
            
            END SUB
            
            '----------------------------------------------------------------
            '----------------------------------------------------------------
            
            SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                GfxDc AS DWORD, Wide AS LONG, High AS LONG)
            
            CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
            CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
            DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
            
            GfxDc = GetDc(GfxHndl)
            
            END SUB
            
            '-----------------------------------------------------------------
            '-----------------------------------------------------------------
            
            SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
            
            LOCAL ClearClr AS DWORD
            
            LOCAL StippleFactor AS INTEGER
            LOCAL StipplePattern AS WORD
            
            StippleFactor = 1
            StipplePattern = &H5555
            
            glColor3Ub(200, 255, 200)
            glEnable(%GL_LINE_STIPPLE)
            
            glPushMatrix
            
            FOR I = -50 TO 50 STEP 10
              glLineStipple(StippleFactor, StipplePattern)
              glBegin(%GL_LINES)
                glVertex2I(-50, I)
                glVertex2I(50, I)
              glEnd
              INCR StippleFactor
            NEXT I
            
            glPopMatrix
            SwapBuffers(GfxDc)
            glDisable(%GL_LINE_STIPPLE)
            glClear(ClearClr)
            
            glFinish
            
            END SUB
            
            '------------------------------------------------------------------
            '------------------------------------------------------------------
            
            SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
            
            LOCAL tPoint AS POINT
            
            GetCursorPos(tPoint)
            ScreenToClient(GfxHndl, tPoint)
            
            tMouse.Mx = tPoint.X
            tMouse.My = tPoint.Y
            
            END SUB
            
            '-------------------------------------------------------------------
            '-------------------------------------------------------------------
            
            SUB glRunDemo(Img() AS BYTE , BYVAL GfxDc AS DWORD)
            
            LOCAL ClearClr AS DWORD
            
            LOCAL AngStep AS LONG
            
            LOCAL Pi  AS SINGLE
            LOCAL Rad AS SINGLE
            LOCAL Z   AS SINGLE
            
            ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                       %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
            
            Pi! = 4 * ATN(1)
            Rad! = Pi! / 180
            AngStep = 8
            AngStep = 360 \ AngStep
            
            J = 1
            
            Again: '
            
            glClear(ClearClr)
            
            glPushMatrix
            
            glTranslateF(0, 0, 0)
            
            Z = -50
            
            glColor3Ub(128, 255, 128)
            
            glBegin(%GL_POLYGON)
            
              FOR I = 0 TO 360 - AngStep STEP AngStep
                X = 30 * SIN(I * Rad!)
                Y = 30 * COS(I * Rad!)
                glVertex3F(X, Y, Z)
                IF I >= 180 THEN Z = 50
              NEXT I
            
            glEnd
            glPopMatrix
            SwapBuffers(GfxDc)
            glClear(ClearClr)
            glFlush
            
            IF J < 2 THEN
              INCR J
              SLEEP 2000
              glEnable(%GL_POLYGON_STIPPLE)
              glPolygonStipple(Img(0))
              GOTO Again
            END IF
            
            glDisable(%GL_POLYGON_STIPPLE)
            glFinish
            
            END SUB
            
            '------------------------------------------------------------------
            '------------------------------------------------------------------
            
            SUB WindowToProjection(X AS DOUBLE, Y AS DOUBLE, Z AS DOUBLE)
            
            '============================================================
            ' Since the orthographic coordinate system does not reflect
            ' the window coordinate system, the window coordinate system
            ' is translated to the ortho system by gluUnProject().
            '
            ' That OpenGL function uses the window values and the values
            ' stored in the viewport matrix, the modle matrix and the
            ' projection matrix to calculate the ortho coordinates.  This
            ' routine can also be used to calculate the perspective view
            ' coordinates.
            '
            ' Because OpenGL uses the various matricies for it's calculations
            ' we have to get those matricies before calling gluUnProject().
            ' That's what the various forms of glGet...() do.  Along with
            ' our window coordinates we pass those matricies to gluUnProject()
            ' and it returns the OGL coordinates in the last three parameters:
            ' WinX, WinY, WinZ.
            '============================================================
            
            LOCAL WinViewport()   AS LONG
            LOCAL ModleMatrix()   AS DOUBLE
            LOCAL ProjectMatrix() AS DOUBLE
            
            LOCAL WinX AS DOUBLE
            LOCAL WinY AS DOUBLE
            LOCAL WinZ AS DOUBLE
            
            DIM WinViewPort(0 TO 1, 0 TO 1)    '<--- 4 element array
            DIM ModleMatrix(0 TO 3, 0 TO 3)    '<--- 16 element array
            DIM ProjectMatrix(0 TO 3, 0 TO 3)
            
            glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
            glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
            glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
            
            gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
            
            X = WinX
            Y = WinY
            Z = WinZ
            
            END SUB
            
            '--------------------------------------------------------
            '--------------------------------------------------------
            
            SUB StippleData(Pattern() AS BYTE)
            
            DATA 00,00,00,00
            DATA 00,00,00,00
            DATA 00,00,00,00
            DATA 00,00,00,00
            DATA 00,00,00,00
            DATA 00,00,00,00
            DATA 00,00,00,00
            DATA 00,00,01,00
            DATA 00,00,07,f0
            DATA f0,00,1f,e0
            DATA 1f,80,1f,c0
            DATA 0f,c0,3f,80
            DATA 07,e0,7e,00
            DATA 03,f0,ff,80
            DATA 03,f5,ff,e0
            DATA 07,fd,ff,f8
            DATA 1f,fc,ff,e8
            DATA ff,e3,bf,70
            DATA de,80,b7,00
            DATA 71,10,4a,80
            DATA 03,10,4e,40
            DATA 02,88,8c,20
            DATA 05,05,04,04
            DATA 02,82,14,40
            DATA 02,04,10,80
            DATA 02,64,1a,80
            DATA 00,92,29,00
            DATA 00,b0,48,00
            DATA 00,c8,90,00
            DATA 00,85,10,00
            DATA 00,03,00,00
            DATA 00,00,10,00
            
            NumDatas = DATACOUNT
            
            REDIM Pattern(NumDatas - 1)
            
            FOR I = 0 TO NumDatas - 1
              Pattern(I) = VAL("&H" + READ$(I + 1))
            NEXT I
            
            END SUB
            Last edited by Walt Decker; 27 Jun 2010, 08:45 AM. Reason: Add additional information
            Walt Decker

            Comment


            • #7
              Some OpenGL Rules

              The code examples in this post switch from a label control to a graphics control.

              Today we will discuss some OpenGL rules. The first is "winding."

              Winding is the direction in which the individual points of an object
              are rendered. For example:
              Code:
                              P1
                                    P2
                              P3
              is clockwise winding while:
              Code:
                              P1
                         P2
                              P3
              is counter-clockwise winding.

              OpenGL uses winding to determine front and back faces. By default,
              front faces are wound counter-clockwise. This can be changed by using
              the glFrontFace() function with an argument of %GL_CW (clockwise) or
              %GL_CCW (counter-clockwise).

              It's important to keep winding consistant. Otherwise you may get
              some unexpected results.

              The following example demonstrates winding.
              Code:
              '=======================================================================
              '                            WINDING
              '-----------------------------------------------------------------------
              '   Winding is the direction in which the individual points of an object
              ' are rendered.  For example:
              '                P1
              '                      P2
              '                P3
              ' is clockwise winding while:
              '                P1
              '           P2
              '                P3
              ' is counter-clockwise winding.
              '
              '   OpenGL uses winding to determine front and back faces.  By default,
              ' front faces are wound counter-clockwise.  This can be changed by using
              ' the glFrontFace() function with an argument of %GL_CW (clockwise) or
              ' %GL_CCW (counter-clockwise).
              '
              '   It's important to keep winding consistant.  Otherwise you may get
              ' some unexpected results.
              '-----------------------------------------------------------------------
              '
              '=======================================================================
              '                            OPENGL FUNCTIONS USED
              '=======================================================================
              ' glViewport()
              ' glMatrixMode()
              ' glLoadIdentity
              ' glOrtho()
              ' glclear()
              ' glPushMatrix
              ' glTranslatef()
              ' glColor3Ub()
              ' glBegin()
              ' glEnd
              ' glVertex2F()
              ' glRotateF()
              ' glPopMatrix
              ' glEnable()
              ' glDisable()
              ' glFlush
              ' glFinish
              ' glFrontFace()
              ' glPolygonMode()
              '=========================================================================
              '                            WINDOWS FUNCTIONS USED
              '=========================================================================
              ' GetDc
              ' ReleaseDc
              ' ChoosePixelFormat
              ' SetPixelFormat
              ' wglCreateContext
              ' wglMakeCurrent
              ' wglDeleteContext
              ' SetWindowLong
              '=========================================================================
              
              #COMPILE EXE
              
              DEFLNG A - Z
              
              #INCLUDE "WIN32API.INC"
              #INCLUDE "gl.inc"
              #INCLUDE "glu.inc"
              
              TYPE MenuFlag_STRUCT
                Winding  AS BIT * 1 IN BYTE
                Surf     AS BIT * 1
                Test     AS BIT * 1
                Back     AS BIT * 1
                Front    AS BIT * 1
                Both     AS BIT * 1
                glRotate AS BIT * 1
              END TYPE
              
              TYPE Angle_STRUCT
                RotX  AS SINGLE
                RotY  AS SINGLE
                RotZ  AS SINGLE
              END TYPE
              
              TYPE OglFlag_STRUCT
                EndProg     AS BIT * 1 IN BYTE
                MouseClk    AS BIT * 1
                OglBtnDead  AS BIT * 1
                RunGlDemo   AS BIT * 1
                MenuFlag_STRUCT
                Angle_STRUCT
              END TYPE
              
              TYPE Single2_STRUCT
                Mx      AS SINGLE
                My      AS SINGLE
              END TYPE
              
              TYPE Mouse_STRUCT
                Single2_STRUCT
                LbDown AS BYTE
              END TYPE
              
              
              MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                        '   correctly while in 2dimensional mode
              
              %GFX_WIN     =    5
              %BTN_END     =    6
              %BTN_OGL     =    7
              
              %MNU_WINDING    = 50
              %MNU_CULL_SURF  = 51
              %MNU_DEPTH_TEST = 52
              %MNU_BACKSIDE   = 53
              %MNU_FRONTSIDE  = 54
              %MNU_BOTH       = 55
              %MNU_ROTATE     = 56
              
              %OGL_ERROR   = %WM_USER + 500
              
              GLOBAL tFlags   AS OglFlag_STRUCT
              GLOBAL tMouse   AS Mouse_STRUCT
              GLOBAL MnuHndl  AS DWORD
              
              DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
              DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
              DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                          GfxDc AS DWORD, Wide AS LONG, High AS LONG)
              
              DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                      BYVAL GfxHndl AS DWORD)
              
              DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
              
              DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
              
              
              DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                          tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
              
              
              DECLARE FUNCTION PBMAIN() AS LONG
              DECLARE CALLBACK FUNCTION Main_CB()
              DECLARE CALLBACK FUNCTION ObjMnu_CB()
              
              FUNCTION PBMAIN()
              
              LOCAL hDlg      AS DWORD
              LOCAL ChilHndl  AS DWORD
              
              LOCAL Txt AS STRING
              
              DIALOG NEW 0, "Exploring Ogl - Ortho Projection - Winding", , , 201, 131, _
                                      %WS_POPUP OR %WS_BORDER _
                                      OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                      %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                      %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                      %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
              
              CONTROL ADD GRAPHIC, hDlg, %GFX_WIN, "", 5, 5, 190, 80, _
                                                       %SS_SUNKEN OR %SS_NOTIFY OR %WS_CHILD OR _
                                                      %WS_VISIBLE
              
              CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
                OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                %WS_EX_LTRREADING
              
              CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
                %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                %WS_EX_LTRREADING
              
              DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
              
              MENU NEW BAR TO MnuHndl
              MENU NEW POPUP TO ChildHndl
              MENU ADD POPUP, MnuHndl, "OGL Image Parameters", ChildHndl, %MF_ENABLED
              
                MENU ADD STRING, ChildHndl, "Change Winding", %MNU_WINDING, %MF_ENABLED, _
                                             CALL ObjMnu_CB
              
                MENU ADD STRING, ChildHndl, "Remove Hidden Surfaces", %MNU_CULL_SURF, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Depth Test", %MNU_DEPTH_TEST, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Lines On Back Side Only", %MNU_BACKSIDE, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Lines On Front Side Only", %MNU_FRONTSIDE, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Lines On Both Sides", %MNU_BOTH, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Rotate", %MNU_ROTATE, %MF_ENABLED, _
                                             CALL ObjMnu_CB
              
              MENU ATTACH MnuHndl, hDlg
              
              DIALOG SHOW MODAL hDlg, CALL Main_CB
              
              END FUNCTION
              
              '------------------------------------------------------------
              '------------------------------------------------------------
              
              CALLBACK FUNCTION Main_CB()
              
              LOCAL lParam AS LONG
              LOCAL wParam AS LONG
              
              SELECT CASE AS LONG CBMSG
              
                wParam = CBWPARAM
                CASE %WM_INITDIALOG
                  GRAPHIC ATTACH CBHNDL, %GFX_WIN
                  GRAPHIC PRINT "Click on the window or"
                  GRAPHIC SET POS (0, 7)
                  GRAPHIC PRINT "select one of the menu items then"
                  GRAPHIC SET POS(0, 15)
                  GRAPHIC PRINT "click on window."
                  GRAPHIC SET POS(0, 40)
                  GRAPHIC PRINT "Hold down left mouse button to rotate"
                  GRAPHIC DETACH
                  CONTROL SET TEXT CBHNDL, %BTN_OGL, "DISABLED"
                  CONTROL DISABLE CBHNDL, %BTN_OGL
                CASE %WM_COMMAND
                  wParam = CBCTLMSG
                  SELECT CASE AS LONG wParam
                    CASE %BN_CLICKED, %STN_CLICKED, 1
                      SELECT CASE AS LONG CBCTL
                        CASE %GFX_WIN
                          IF Tflags.RunGlDemo THEN EXIT SELECT
                          tFlags.MouseClk = 1
                          CALL RunOgl(CBHNDL)
                          FUNCTION = 1
                          EXIT FUNCTION
              
                        CASE %BTN_END
                          tFlags.EndProg = 1
                          CALL RunOgl(CBHNDL)
                          DIALOG END CBHNDL
                          FUNCTION = 1
                          EXIT FUNCTION
              
                        CASE %BTN_OGL
                          CONTROL DISABLE CBHNDL, %BTN_OGL
                          tFlags.OglBtnDead = 1
                          tFlags.RunGlDemo = 1
                          CALL RunOgl(CBHNDL)
                          FUNCTION = 1
                          EXIT FUNCTION
              
                      END SELECT
                  END SELECT
              
                CASE %WM_DESTROY
                  IF tFlags.EndProg THEN EXIT SELECT
                  tFlags.EndProg = 1
                  CALL RunOgl(CBHNDL)
              
                CASE %OGL_ERROR
                  SELECT CASE wParam
                    CASE 1
                      MSGBOX "Could not find matching pixel format"
                    CASE 2
                      MSGBOX "Could not set selected pixel format"
                    CASE 3
                      MSGBOX "Could not create rendering context"
                    CASE 4
                      MSGBOX "Could not make rendering context current.  Defined window may not" _
                             + " support it"
                  END SELECT
                  DIALOG END CBHNDL
              END SELECT
              
              END FUNCTION
              
              '------------------------------------------------------------
              '------------------------------------------------------------
              
              CALLBACK FUNCTION ObjMnu_CB()
              
              IF CBMSG = %WM_COMMAND THEN
                IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
              
                  SELECT CASE CBCTL
                    CASE %MNU_WINDING
                      IF tFlags.Winding = 1 THEN
                        tFlags.Winding = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.Winding = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                    CASE %MNU_CULL_SURF
                      IF tFlags.Surf = 1 THEN
                        tFlags.Surf= 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.Surf = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                    CASE %MNU_DEPTH_TEST
                      IF tFlags.Test = 1 THEN
                        tFlags.Test = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.Test = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                    CASE %MNU_BACKSIDE
                      IF tFlags.Back THEN
                        tFlags.Back = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.Back = 1
                      tFlags.Front = 0
                      tFlags.Both = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_FRONTSIDE
                      IF tFlags.Front THEN
                        tFlags.Front = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.Back = 0
                      tFlags.Front = 1
                      tFlags.Both = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_BOTH
                      IF tFlags.Both THEN
                        tFlags.Both = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.Back = 0
                      tFlags.Front = 0
                      tFlags.Both = 1
                      MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_CHECKED OR %MF_ENABLED
              
                    CASE %MNU_ROTATE
                      IF tFlags.glRotate THEN
                        tFlags.glrotate = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATE, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.glRotate = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATE, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                  END SELECT
                END IF
              END IF
              
              END FUNCTION
              '------------------------------------------------------------
              '------------------------------------------------------------
              
              SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
              
              '==============================================================
              ' This is the 1st step in setting up windows for OpenGl support
              ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
              ' graphics
              '==============================================================
              
              pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
              pfd.nversion = 1
              pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
              pfd.dwlayermask = %PFD_MAIN_PLANE
              pfd.ipixeltype = %PFD_TYPE_RGBA
              pfd.ccolorbits = 24
              pfd.cdepthbits = 24
              pfd.caccumbits = 0
              pfd.cstencilbits = 0
              
              END SUB
              
              '---------------------------------------------------------------
              '---------------------------------------------------------------
              
              SUB RunOgl(BYVAL Hndl AS DWORD)
              
              STATIC Wide  AS LONG
              STATIC High  AS LONG
              
              STATIC GfxDC     AS DWORD
              STATIC OglRc     AS DWORD
              STATIC GfxHndl   AS DWORD
              
              LOCAL Proc AS DWORD
              
              LOCAL Img() AS BYTE
              
              LOCAL X     AS DOUBLE
              LOCAL Y     AS DOUBLE
              LOCAL Z     AS DOUBLE
              
              LOCAL Lx    AS SINGLE
              LOCAL Ly    AS SINGLE
              
              LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
              
              IF ISFALSE(GfxDc) THEN
                IF tFlags.EndProg THEN EXIT SUB
              
                CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                CALL OglPixFormat(tPixFmt)
              
                OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
              
                IF OglRc = 0 THEN EXIT SUB
              
                CALL SetOglWindow(Wide, High, 100)
              
              END IF
              
              IF tFlags.EndProg THEN
                CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                EXIT SUB
              END IF
              
              IF tFlags.MouseClk THEN
                IF tFlags.glRotate THEN
                  Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, CODEPTR(Mouse_SubCB))
                  CONTROL SET USER Hndl, %GFX_WIN, 1, Proc
                  CALL Mouse(GfxHndl, 0)
                  X = tMouse.Mx
                                        '==========================================
                                        ' Since windows places 0,0 at the upper
                  Y = High - tMouse.My  ' left corner of the display and Ogl locates
                                        ' 0,0 at the lower left corner the Y coordinate
                                        ' must be adjusted.
                                        '==========================================
              
                  CALL OglRenderImage(X, Y, GfxDc)
              
                  DO
                    tFlags.MouseClk = 0
                    DIALOG DOEVENTS
                    IF tFlags.EndProg THEN EXIT DO
                    IF tMouse.LbDown THEN
                      CALL Mouse(GfxHndl, 0)
                      IF Lx! = tMouse.Mx AND Ly! = tMouse.My THEN
                        ITERATE DO
                      ELSE
                        Lx! = tMouse.Mx
                        Ly! = tMouse.My
                      END IF
                      X = tMouse.Mx
                      Y = High - tMouse.My
                      CALL OglRenderImage(X, Y, GfxDc)
                    END IF
                  LOOP WHILE tMouse.LbDown OR tFlags.MouseClk = 0
              
                  CALL SetWindowLong(GfxHndl, %GWL_WNDPROC, Proc)
                  tFlags.MouseClk = 0
                  EXIT SUB
              
                END IF
              END IF
              
              CALL OglRenderImage(X, Y, GfxDc)
              tFlags.MouseClk = 0
              
              END SUB
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                  tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
              
              '================================================================
              '  This is the second step for OpenGL support
              '  ChoosePixelFormat selects a pixel format that matches that
              '  described in the PIXELFORMATDESCRIPTOR structure.
              '
              '  Each step in the setup is quried because not all windows support
              '  OpenGL rendering
              '================================================================
              
              LOCAL PixFormat AS DWORD
              LOCAL OglRc     AS DWORD
              
              LOCAL T AS LONG
              
              PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
              
              IF ISFALSE (PixFormat) THEN
                DIALOG POST Hndl, %OGL_ERROR, 1, 0
                EXIT FUNCTION
              END IF
              
              t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
              
              IF ISFALSE(t) THEN
                DIALOG POST Hndl, %OGL_ERROR, 2, 0
                EXIT FUNCTION
              END IF
              
              OglRc = wglCreateContext(GfxDc)
              
              IF ISFALSE(OglRc) THEN
                DIALOG POST Hndl, %OGL_ERROR, 3, 0
                EXIT FUNCTION
              END IF
              
              t = wglMakeCurrent(GfxDc, OglRc)
              
              IF ISFALSE(t) THEN
                DIALOG POST Hndl, %OGL_ERROR, 4, 0
                EXIT FUNCTION
              END IF
              
              SetOglPipe = OglRc
              END FUNCTION
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                               BYVAL OrthoRange AS LONG)
              
              LOCAL ClearClr AS DWORD
              
              LOCAL Aspect AS SINGLE
              LOCAL Xmin   AS SINGLE
              LOCAL Ymin   AS SINGLE
              LOCAL Xmax   AS SINGLE
              LOCAL Ymax   AS SINGLE
              LOCAL Zmin   AS SINGLE
              LOCAL Zmax   AS SINGLE
              
              '=================================================================
              ' This defines the graphics environment.
              ' Getting this correct is crucial to using OpenGL.
              '
              ' In previous examples the orthographic projection was set to the
              ' window coordinates.  This now changes the projection coordinates
              ' to something other than the window coordinates.
              '=================================================================
              
              ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                         %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
              
              IF Wide <= High THEN
                Aspect! = High / Wide
              ELSE
                Aspect! = Wide / High
              END IF
              
              IF Wide <= High THEN
                Xmin! = -OrthoRange / 2
                Xmax! = OrthoRange  / 2
                Ymin! = (-OrthoRange / 2) * Aspect!
                Ymax! = (OrthoRange / 2) * Aspect!
              ELSE
                Xmin! = (-OrthoRange / 2) * Aspect!
                Xmax! = (OrthoRange / 2) * Aspect!
                Ymin! = (-OrthoRange / 2)
                Ymax! = (OrthoRange  / 2)
              END IF
              
              Zmin! = -OrthoRange
              Zmax! = OrthoRange / 2
              
              glViewport(0, 0, Wide, High)
              glMatrixMode(%GL_PROJECTION)
              glLoadIdentity
              glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
              glMatrixMode(%GL_MODELVIEW)
              glLoadIdentity
              glClear(ClearClr)
              
              END SUB
              
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
              
              wglMakeCurrent(0, 0)
              wglDeleteContext(OglRc)
              ReleaseDc(GfxHndl,GfxDc)
              
              END SUB
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                  GfxDc AS DWORD, Wide AS LONG, High AS LONG)
              
              CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
              CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
              DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
              
              GfxDc = GetDc(GfxHndl)
              
              END SUB
              
              '-----------------------------------------------------------------
              '-----------------------------------------------------------------
              
              SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
              
              LOCAL ClearClr AS DWORD
              
              LOCAL Pi      AS SINGLE
              LOCAL Rad     AS SINGLE
              LOCAL Angle   AS SINGLE
              LOCAL AngStep AS SINGLE
              
              LOCAL Z  AS DOUBLE
              
              LOCAL Pivot AS BYTE
              LOCAL R     AS BYTE
              LOCAL G     AS BYTE
              LOCAL B     AS BYTE
              LOCAL Flip  AS BYTE
              
              STATIC Lx AS SINGLE
              STATIC Ly AS SINGLE
              STATIC Lz AS SINGLE
              
              LOCAL AngStart AS SINGLE
              LOCAL AngEnd   AS SINGLE
              
              ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT  OR _
                         %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
              
              Pi! = 4 * ATN(1)
              Rad! = Pi! / 180
              Deg! = 180 / Pi!
              AngStep! = 22.5!
              Pivot = 1
              AngStart = 0.0!
              AngEnd = 180.0!
              
              IF tFlags.glRotate THEN
                CALL WindowToProjection(X, Y, Z)
                IF X = Lx! AND Y = Ly! THEN EXIT IF
                Lx! = X - Lx!
                Ly! = Y - Ly!
                tFlags.RotX! = tFlags.RotX! - Lx!
                tFlags.RotY! = tFlags.RotY! - Ly!
                Lx! = X
                Ly! = Y
              ELSE
                Lx! = 0.0!
                Ly! = 0.0!
                tFlags.RotX! = 0.0!
                tFlags.RotY! = 0.0!
              END IF
              
              glClear(ClearClr)
              
              IF tFlags.Winding THEN
                glFrontFace(%GL_CW)
              END IF
              
              IF tFlags.Surf THEN
                glEnable(%GL_CULL_FACE)
              END IF
              
              IF tFlags.Test THEN
                glEnable(%GL_DEPTH_TEST)
              END IF
              
              IF tFlags.Back = 1 THEN
                glPolygonMode(%GL_BACK, %GL_LINE)
              END IF
              
              IF tFlags.Front = 1 THEN
                glPolygonMode(%GL_FRONT, %GL_LINE)
              END IF
              
              IF tFlags.Both = 1 THEN
                glPolygonMode(%GL_FRONT_AND_BACK, %GL_LINE)
              END IF
              
              Again: '
              
              glPushMatrix
              
              IF tFlags.glRotate THEN
                glRotateF(tFlags.RotX!, 1, 0, 0)
                glRotateF(tFlags.RotY!, 0, 1, 0)
              END IF
              
              glBegin(%GL_TRIANGLE_FAN)
              
                '==================================================================
                ' Since we are using a triangle fan, this gives all verticies a
                ' common origin.  Using -100 for the Z factor produces a hole in
                ' the cone because it is beyond the "NEAR" parameter of the
                ' orthographic projection limit.
                '==================================================================
              
                glVertex3F(0, 0, -100)
              
                '==================================================================
              
                FOR Angle! = AngStart! TO AngEnd! STEP AngStep!
                  X = 40 * SIN(Angle! * Rad!)
                  Y = 40 * COS(Angle! * Rad!)
              
                  IF Pivot = 2 THEN
                    R = 255
                    G = 0
                    B = 0
                    IF Angle! >= 180.0! THEN
                      R = 0
                      G = 100
                      B = 255
                    END IF
                    glColor3Ub(R, G, B)
                    Pivot = 1
                  ELSE
                    R = 0
                    G = 255
                    B = 0
                    IF Angle! >= 180.0! THEN
                      R = 200
                      G = 200
                      B = 100
                    END IF
                    glColor3Ub(R, G, B)
                    INCR Pivot
                  END IF
              
                  glVertex2F(X, Y)
                NEXT Angle!
              glEnd
              glPopMatrix
              
              '======================================================
              ' This changes the winding of the left half of the cone.
              ' When the cone is rotated, if "remove hidden surfaces" is
              ' enabled there will be two sections removed instead of one.
              ' Also, if "lines on backside" or "lines on frontside" is
              ' enabled, you will see two sections of lines instead of one.
              '======================================================
              
              IF Flip < 1 THEN
                INCR Flip
                AngStart! = 360!
                AngEnd! = 180!
                AngStep! = -AngStep
                GOTO Again
              END IF
              
              SwapBuffers(GfxDc)
              glClear(ClearClr)
              
              glFlush
              
              glFrontFace(%GL_CCW)
              glDisable(%GL_CULL_FACE)
              glDisable(%GL_DEPTH_TEST)
              glPolygonMode(%GL_FRONT_AND_BACK, %GL_FILL)
              
              glFinish
              
              END SUB
              
              '------------------------------------------------------------------
              '------------------------------------------------------------------
              
              SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
              
              LOCAL tPoint AS POINT
              
              GetCursorPos(tPoint)
              ScreenToClient(GfxHndl, tPoint)
              
              tMouse.Mx = tPoint.X
              tMouse.My = tPoint.Y
              
              END SUB
              
              '-------------------------------------------------------------------
              '-------------------------------------------------------------------
              
              CALLBACK FUNCTION Mouse_SubCB
              
              LOCAL Hndl      AS DWORD
              LOCAL OrigProc  AS DWORD
              LOCAL Gfx_Hndl  AS DWORD
              
              Hndl = CBHNDL
              Gfx_Hndl = GetDlgCtrlId(Hndl)
              OrigProc = GetParent(Hndl)
              CONTROL GET USER OrigProc, Gfx_Hndl, 1 TO OrigProc
              IF OrigProc = 0 THEN EXIT FUNCTION
              
              SELECT CASE CBMSG
                CASE IS %WM_LBUTTONDOWN
                  tMouse.LbDown = 1
                  tFlags.MouseClk = 0
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_LBUTTONUP
                  tMouse.LbDown = 0
                  tFlags.MouseClk = 1
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_RBUTTONDOWN
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_RBUTTONUP
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_MOUSEMOVE
                  IF (CBWPARAM AND %MK_LBUTTON) = %MK_LBUTTON THEN
                    tMouse.LbDown = 1
                    tFlags.MouseClk = 0
                  ELSE
                    tMouse.LbDown = 0
                    tFlags.MouseClk = 1
                  END IF
              END SELECT
              
              FUNCTION = CallWindowProc(OrigProc, Hndl, CBMSG, CBWPARAM, CBLPARAM)
              END FUNCTION
              
              '------------------------------------------------------------------
              '------------------------------------------------------------------
              
              SUB WindowToProjection(X AS DOUBLE, Y AS DOUBLE, Z AS DOUBLE)
              
              '============================================================
              ' Since the orthographic coordinate system does not reflect
              ' the window coordinate system, the window coordinate system
              ' is translated to the ortho system by gluUnProject().
              '
              ' That OpenGL function uses the window values and the values
              ' stored in the viewport matrix, the modle matrix and the
              ' projection matrix to calculate the ortho coordinates.  This
              ' routine can also be used to calculate the perspective view
              ' coordinates.
              '
              ' Because OpenGL uses the various matricies for it's calculations
              ' we have to get those matricies before calling gluUnProject().
              ' That's what the various forms of glGet...() do.  Along with
              ' our window coordinates we pass those matricies to gluUnProject()
              ' and it returns the OGL coordinates in the last three parameters:
              ' WinX, WinY, WinZ.
              '============================================================
              
              LOCAL WinViewport()   AS LONG
              LOCAL ModleMatrix()   AS DOUBLE
              LOCAL ProjectMatrix() AS DOUBLE
              
              LOCAL WinX AS DOUBLE
              LOCAL WinY AS DOUBLE
              LOCAL WinZ AS DOUBLE
              
              DIM WinViewPort(0 TO 1, 0 TO 1)    '<--- 4 element array
              DIM ModleMatrix(0 TO 3, 0 TO 3)    '<--- 16 element array
              DIM ProjectMatrix(0 TO 3, 0 TO 3)
              
              glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
              glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
              glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
              
              gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
              
              X = WinX
              Y = WinY
              Z = WinZ
              
              END SUB
              
              '--------------------------------------------------------
              '--------------------------------------------------------
              In OpenGL there are two types of polygons, valid and invalid.
              Although OpenGL can render with both types, it cannot render invalid
              polygons properly, so there are two rules that should be followed,
              otherwise unexpected results will occur.

              The first rule is that all polygons must reside in a single plane,
              i.e., they cannot be twisted. For example:
              Code:
                           P1..........P2
                           .           .
                           P4..........P3
              is a valid polygon because all points are in a single plane while
              Code:
                           P1..........P2
                                  .
                           P3..........P4
              is not because there is a twist in the polygon.

              The second rule is that all polygons must be convex, i.e., they
              cannot have holes in them. For example:
              Code:
                           P1............P2
                                            .
                              .                P3
                                    P4      .
              is a valid polygon whereas:
              Code:
                          P1.............P2
                            .          .
                                .   P3
                                    . .
                                       P4
              is not because it has an indentaion.

              To insure that polygons follow these rules, triangles should be used
              as much as possible, since there is no triangle that can be twisted or
              have a hole in it.

              The following code example demonstrates both valid and invalid polygons.

              Code:
              '=======================================================================
              '                         VALID AND INVALID POLYGONS
              '-----------------------------------------------------------------------
              '   In OpenGL there are two types of polygons, valid and invalid.
              ' Although OpenGL can render with both types, it cannot render invalid
              ' polygons properly, so there are two rules that should be followed,
              ' otherwise unexpected results will occur.
              '
              '   The first rule is that all polygons must reside in a single plane,
              ' i.e., they cannot be twisted. For example:
              '             P1..........P2
              '             .           .
              '             P4..........P3
              ' is a valid polygon because all points are in a single plane while
              '             P1..........P2
              '                    .
              '             P3..........P4
              ' is not because there is a twist in the polygon.
              '
              '   The second rule is that all polygons must be convex, i.e., they
              ' cannot have holes in them.  For example:
              '             P1............P2
              '                              .
              '                .                P3
              '                      P4      .
              ' is a valid polygon whereas:
              '            P1.............P2
              '              .          .
              '                  .   P3
              '                      . .
              '                         P4
              ' is not because it has an indentaion.
              '
              '   To insure that polygons follow these rules, triangles should be used
              ' as much as possible, since there is no triangle that can be twisted or
              ' have a hole in it.
              '-----------------------------------------------------------------------
              '
              '=======================================================================
              '                            OPENGL FUNCTIONS USED
              '=======================================================================
              ' glViewport()
              ' glMatrixMode()
              ' glLoadIdentity
              ' glOrtho()
              ' glclear()
              ' glPushMatrix
              ' glTranslatef()
              ' glRotateF()
              ' glColor3Ub()
              ' glBegin()
              ' glEnd
              ' glVertex3F()
              ' glPopMatrix
              ' glEnable()
              ' glDisable()
              ' glFlush
              ' glFinish
              '=========================================================================
              '                            WINDOWS FUNCTIONS USED
              '=========================================================================
              ' GetDc
              ' ReleaseDc
              ' ChoosePixelFormat
              ' SetPixelFormat
              ' wglCreateContext
              ' wglMakeCurrent
              ' wglDeleteContext
              '=========================================================================
              
              #COMPILE EXE
              
              DEFLNG A - Z
              
              #INCLUDE "WIN32API.INC"
              #INCLUDE "gl.inc"
              #INCLUDE "glu.inc"
              
              TYPE MenuFlag_STRUCT
                Winding   AS BIT * 1 IN BYTE
                Surf      AS BIT * 1
                Test      AS BIT * 1
                Back      AS BIT * 1
                Front     AS BIT * 1
                Both      AS BIT * 1
                Examples  AS BIT * 1
              END TYPE
              
              TYPE Rotate_STRUCT
                RotX  AS BIT * 1 IN BYTE
                RotY  AS BIT * 1
                RotZ  AS BIT * 1
                RotA  AS BIT * 1
              END TYPE
              
              TYPE OglFlag_STRUCT
                EndProg     AS BIT * 1 IN BYTE
                MouseClk    AS BIT * 1
                OglBtnDead  AS BIT * 1
                RunGlDemo   AS BIT * 1
                MenuFlag_STRUCT
                Rotate_STRUCT
              END TYPE
              
              TYPE Button_STRUCT
                LbDown AS BIT * 1 IN BYTE
                LbClk  AS BIT * 1
                RbDown AS BIT * 1
                RbClk  AS BIT * 1
              END TYPE
              
              TYPE Single2_STRUCT
                Mx  AS SINGLE
                My  AS SINGLE
              END TYPE
              
              TYPE Mouse_STRUCT
                Single2_STRUCT
                Button_STRUCT
              END TYPE
              
              
              MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                        '   correctly while in 2dimensional mode
              
              %GFX_WIN     =    5
              %BTN_END     =    6
              %BTN_OGL     =    7
              
              %MNU_WINDING    = 50
              %MNU_CULL_SURF  = 51
              %MNU_DEPTH_TEST = 52
              %MNU_BACKSIDE   = 53
              %MNU_FRONTSIDE  = 54
              %MNU_BOTH       = 55
              %MNU_ROTATE     = 56
              %MNU_ROTATEX    = 57
              %MNU_ROTATEY    = 58
              %MNU_ROTATEZ    = 59
              %MNU_ROTATEALL  = 60
              %MNU_EXAMPLES   = 61
              
              %OGL_ERROR   = %WM_USER + 500
              
              GLOBAL tFlags AS OglFlag_STRUCT
              GLOBAL tMouse AS Mouse_STRUCT
              GLOBAL MnuHndl AS DWORD
              
              DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
              DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
              DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                          GfxDc AS DWORD, Wide AS LONG, High AS LONG)
              
              DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                      BYVAL GfxHndl AS DWORD)
              
              DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
              
              DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
              
              
              DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                          tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
              
              
              DECLARE FUNCTION PBMAIN() AS LONG
              DECLARE CALLBACK FUNCTION Main_CB()
              
              FUNCTION PBMAIN()
              
              LOCAL hDlg  AS DWORD
              LOCAL Txt AS STRING
              
              DIALOG NEW 0, "Exploring Ogl - Valid & Invalid Polygons", , , 201, 131, _
                                      %WS_POPUP OR %WS_BORDER _
                                      OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                      %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                      %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                      %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
              
              CONTROL ADD GRAPHIC, hDlg, %GFX_WIN, "", 5, 5, 190, 80, _
                                                       %SS_SUNKEN OR %SS_NOTIFY OR %WS_CHILD OR _
                                                      %WS_VISIBLE
              
              CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
                OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                %WS_EX_LTRREADING
              
              CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
                %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                %WS_EX_LTRREADING
              
              DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
              
              MENU NEW BAR TO MnuHndl
              MENU NEW POPUP TO ChildHndl
              MENU ADD POPUP, MnuHndl, "OGL Image Parameters", ChildHndl, %MF_ENABLED
              
                MENU ADD STRING, ChildHndl, "Change Winding", %MNU_WINDING, %MF_ENABLED, _
                                             CALL ObjMnu_CB
              
                MENU ADD STRING, ChildHndl, "Remove Hidden Surfaces", %MNU_CULL_SURF, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Depth Test", %MNU_DEPTH_TEST, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Lines On Back Side Only", %MNU_BACKSIDE, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Lines On Front Side Only", %MNU_FRONTSIDE, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                MENU ADD STRING, ChildHndl, "Lines On Both Sides", %MNU_BOTH, %MF_ENABLED OR %MF_CHECKED, _
                                             CALL ObjMnu_CB
                MENU NEW POPUP TO ChildHndl_2
                MENU ADD POPUP, ChildHndl, "Rotate", ChildHndl_2, %MF_ENABLED
                  MENU ADD STRING, ChildHndl_2, "Around X Axsis", %MNU_ROTATEX, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl_2, "Around Y Axsis", %MNU_ROTATEY, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl_2, "Around Z Axsis", %MNU_ROTATEZ, %MF_ENABLED, _
                                             CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl_2, "Around All", %MNU_ROTATEALL, %MF_ENABLED, _
                                             CALL ObjMnu_CB
              MENU ADD STRING, MnuHndl, "Examples", %MNU_EXAMPLES, %MF_ENABLED, _
                                             CALL ObjMnu_CB
              
              MENU ATTACH MnuHndl, hDlg
              
              DIALOG SHOW MODAL hDlg, CALL Main_CB
              
              END FUNCTION
              
              '------------------------------------------------------------
              '------------------------------------------------------------
              
              CALLBACK FUNCTION Main_CB()
              
              LOCAL lParam AS LONG
              LOCAL wParam AS LONG
              
              SELECT CASE AS LONG CBMSG
              
                wParam = CBWPARAM
                CASE %WM_INITDIALOG
                  tFlags.Both = 1
                CASE %WM_COMMAND
                  wParam = CBCTLMSG
                  SELECT CASE AS LONG wParam
                    CASE %BN_CLICKED, %STN_CLICKED, 1
                      SELECT CASE AS LONG CBCTL
                        CASE %GFX_WIN
              
                        CASE %BTN_END
                          tFlags.EndProg = 1
                          CALL RunOgl(CBHNDL)
                          DIALOG END CBHNDL
                          FUNCTION = 1
                          EXIT FUNCTION
              
                        CASE %BTN_OGL
                          CONTROL DISABLE CBHNDL, %BTN_OGL
                          tFlags.OglBtnDead = 1
                          tFlags.RunGlDemo = 1
                          CALL RunOgl(CBHNDL)
                          FUNCTION = 1
                          EXIT FUNCTION
              
                      END SELECT
                  END SELECT
              
                CASE %WM_DESTROY
                  IF tFlags.EndProg THEN EXIT SELECT
                  tFlags.EndProg = 1
                  CALL RunOgl(CBHNDL)
              
                CASE %OGL_ERROR
                  SELECT CASE wParam
                    CASE 1
                      MSGBOX "Could not find matching pixel format"
                    CASE 2
                      MSGBOX "Could not set selected pixel format"
                    CASE 3
                      MSGBOX "Could not create rendering context"
                    CASE 4
                      MSGBOX "Could not make rendering context current.  Defined window may not" _
                             + " support it"
                  END SELECT
                  DIALOG END CBHNDL
              END SELECT
              
              END FUNCTION
              
              '------------------------------------------------------------
              '------------------------------------------------------------
              
              SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
              
              '==============================================================
              ' This is the 1st step in setting up windows for OpenGl support
              ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
              ' graphics
              '==============================================================
              
              pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
              pfd.nversion = 1
              pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
              pfd.dwlayermask = %PFD_MAIN_PLANE
              pfd.ipixeltype = %PFD_TYPE_RGBA
              pfd.ccolorbits = 24
              pfd.cdepthbits = 24
              pfd.caccumbits = 0
              pfd.cstencilbits = 0
              
              END SUB
              
              '---------------------------------------------------------------
              '---------------------------------------------------------------
              
              SUB RunOgl(BYVAL Hndl AS DWORD)
              
              STATIC Wide  AS LONG
              STATIC High  AS LONG
              
              STATIC GfxDC     AS DWORD
              STATIC OglRc     AS DWORD
              STATIC GfxHndl   AS DWORD
              
              LOCAL Img() AS BYTE
              
              LOCAL X     AS DOUBLE
              LOCAL Y     AS DOUBLE
              LOCAL Z     AS DOUBLE
              
              LOCAL Azi AS LONG
              LOCAL Lazi AS LONG
              
              LOCAL HalfWide AS LONG
              LOCAL HalfHigh AS LONG
              
              LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
              
              IF tFlags.Examples THEN
                IF ISTRUE(GfxDc) THEN
                  CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                  GfxDc = 0
                  OglRc = 0
                ELSE
                  CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                  ReleaseDc(GfxHndl, GfxDc)
                  GfxDc = 0
                END IF
                CALL Examples(GfxHndl, Hndl)
                EXIT SUB
              END IF
              
              IF ISFALSE(GfxDc) THEN
                IF tFlags.EndProg THEN EXIT SUB
              
                CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                CALL OglPixFormat(tPixFmt)
              
                OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
              
                IF OglRc = 0 THEN EXIT SUB
              
                CALL SetOglWindow(Wide, High, 100)
              
              END IF
              
              IF tFlags.EndProg THEN
                CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                EXIT SUB
              END IF
              
              IF tFlags.RunGlDemo THEN
                HalfWide = Wide \ 2
                HalfHigh = High \ 2
                CALL glRunDemo(Azi, GfxDc)
                SLEEP 50
                Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, CODEPTR(Mouse_SubCB))
                CONTROL SET USER Hndl, %GFX_WIN, 1, Proc
                DO
                  DIALOG DOEVENTS
              
                  IF tFlags.EndProg THEN
                    CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                    EXIT DO
                  END IF
              
                  IF tMouse.LbDown = 0 THEN ITERATE DO
              
                  DO
                    DIALOG DOEVENTS
                    CALL Mouse(GfxHndl, 0)
                    Azi = Az(HalfWide, HalfHigh, tMouse.Mx, tMouse.My)
                    CALL glRunDemo(Azi, GfxDc)
                  LOOP UNTIL tMouse.LbDown = 0 OR tFlags.EndProg = 1
                LOOP
              END IF
              
              SetWindowLong(GfxHndl, %GWL_WNDPROC, Proc)
              CONTROL SET USER Hndl, %GFX_WIN, 1, 0
              
              END SUB
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                  tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
              
              '================================================================
              '  This is the second step for OpenGL support
              '  ChoosePixelFormat selects a pixel format that matches that
              '  described in the PIXELFORMATDESCRIPTOR structure.
              '
              '  Each step in the setup is quried because not all windows support
              '  OpenGL rendering
              '================================================================
              
              LOCAL PixFormat AS DWORD
              LOCAL OglRc     AS DWORD
              
              LOCAL T AS LONG
              
              PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
              
              IF ISFALSE (PixFormat) THEN
                DIALOG POST Hndl, %OGL_ERROR, 1, 0
                EXIT FUNCTION
              END IF
              
              t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
              
              IF ISFALSE(t) THEN
                DIALOG POST Hndl, %OGL_ERROR, 2, 0
                EXIT FUNCTION
              END IF
              
              OglRc = wglCreateContext(GfxDc)
              
              IF ISFALSE(OglRc) THEN
                DIALOG POST Hndl, %OGL_ERROR, 3, 0
                EXIT FUNCTION
              END IF
              
              t = wglMakeCurrent(GfxDc, OglRc)
              
              IF ISFALSE(t) THEN
                DIALOG POST Hndl, %OGL_ERROR, 4, 0
                EXIT FUNCTION
              END IF
              
              SetOglPipe = OglRc
              END FUNCTION
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                               BYVAL OrthoRange AS LONG)
              
              LOCAL ClearClr AS DWORD
              
              LOCAL Aspect AS SINGLE
              LOCAL Xmin   AS SINGLE
              LOCAL Ymin   AS SINGLE
              LOCAL Xmax   AS SINGLE
              LOCAL Ymax   AS SINGLE
              LOCAL Zmin   AS SINGLE
              LOCAL Zmax   AS SINGLE
              
              '=================================================================
              ' This defines the graphics environment.
              ' Getting this correct is crucial to using OpenGL.
              '
              ' In previous examples the orthographic projection was set to the
              ' window coordinates.  This now changes the projection coordinates
              ' to something other than the window coordinates.
              '=================================================================
              
              ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                         %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
              
              IF Wide <= High THEN
                Aspect! = High / Wide
              ELSE
                Aspect! = Wide / High
              END IF
              
              IF Wide <= High THEN
                Xmin! = -OrthoRange / 2
                Xmax! = OrthoRange  / 2
                Ymin! = (-OrthoRange / 2) * Aspect!
                Ymax! = (OrthoRange / 2) * Aspect!
              ELSE
                Xmin! = (-OrthoRange / 2) * Aspect!
                Xmax! = (OrthoRange / 2) * Aspect!
                Ymin! = (-OrthoRange / 2)
                Ymax! = (OrthoRange  / 2)
              END IF
              
              Zmin! = -OrthoRange / 2
              Zmax! = OrthoRange
              
              glViewport(0, 0, Wide, High)
              glMatrixMode(%GL_PROJECTION)
              glLoadIdentity
              glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
              glMatrixMode(%GL_MODELVIEW)
              glLoadIdentity
              glClear(ClearClr)
              
              END SUB
              
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
              
              wglMakeCurrent(0, 0)
              wglDeleteContext(OglRc)
              ReleaseDc(GfxHndl,GfxDc)
              
              END SUB
              
              '----------------------------------------------------------------
              '----------------------------------------------------------------
              
              SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                  GfxDc AS DWORD, Wide AS LONG, High AS LONG)
              
              CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
              CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
              DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
              
              GfxDc = GetDc(GfxHndl)
              
              END SUB
              
              '-----------------------------------------------------------------
              '-----------------------------------------------------------------
              
              SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
              
              LOCAL tPoint AS POINT
              
              GetCursorPos(tPoint)
              ScreenToClient(GfxHndl, tPoint)
              
              tMouse.Mx = tPoint.X
              tMouse.My = tPoint.Y
              
              END SUB
              
              '-------------------------------------------------------------------
              '-------------------------------------------------------------------
              
              SUB glRunDemo(BYVAL Azi AS LONG , BYVAL GfxDc AS DWORD)
              
              LOCAL ClearClr AS DWORD
              
              LOCAL AngStep AS LONG
              
              LOCAL Pi    AS SINGLE
              LOCAL Rad   AS SINGLE
              LOCAL Z     AS SINGLE
              
              ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                         %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
              
              Pi! = 4 * ATN(1)
              Rad! = Pi! / 180
              AngStep = 8
              AngStep = 360 \ AngStep
              
              IF tFlags.Winding THEN
                glFrontFace(%GL_CW)
              END IF
              
              IF tFlags.Surf THEN
                glEnable(%GL_CULL_FACE)
              END IF
              
              IF tFlags.Test THEN
                glEnable(%GL_DEPTH_TEST)
              END IF
              
              IF tFlags.Back = 1 THEN
                glPolygonMode(%GL_BACK, %GL_LINE)
              END IF
              
              IF tFlags.Front = 1 THEN
                glPolygonMode(%GL_FRONT, %GL_LINE)
              END IF
              
              IF tFlags.Both = 1 THEN
                glPolygonMode(%GL_FRONT_AND_BACK, %GL_LINE)
              END IF
              
              '===========================================================
              ' This is a valid polygon.  It can be normalize and is convex.
              ' Ogl has no problem rendering it correctly no matter what is
              ' done to it
              '===========================================================
              
              glPushMatrix
              glTranslateF(75, 0, 0)
              glColor3Ub(128, 255, 200)
              
              IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
              IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
              IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
              IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
              
              glBegin(%GL_POLYGON)
              FOR I = 0 TO 360 - AngStep STEP AngStep
                X = 30 * SIN(I * Rad!)
                Y = 30 * COS(I * Rad!)
                glVertex3F(X, Y, Z)
              NEXT I
              glEnd
              glPopMatrix
              
              '======================================================
              ' This is an invalid polygon because it resides in two
              ' planes, i.e., the verticies cross; therefore it cannot
              ' be normalized and Ogl has problems rendering it correctly.
              ' That is shown the next demo when a Z factor is added.
              '======================================================
              
              glPushMatrix
              glTranslateF(35, 0, 0)
              glColor3Ub(255, 128, 200)
              
              IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
              IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
              IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
              IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
              
              glBegin(%GL_QUADS)
                glVertex3F(-35, 35, 0)
                glVertex3F(05, -35, 0)
                glVertex3F(-35, -35, 0)
                glVertex3F(05, 35, 0)
              glEnd
              glPopMatrix
              
              '========================================================
              ' This is an invalid polygon.  Although no verticies cross,
              ' it is not convex; therefore Ogl has problems rendering it
              ' correctly.
              '========================================================
              
              glPushMatrix
              glTranslateF(-65, 0, 0)
              glColor3Ub(126, 0, 200)
              
              IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
              IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
              IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
              IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
              
              glBegin(%GL_POLYGON)
                glVertex3F(-35, 35, 0)
                glVertex3F(-15, 15, 0)
                glVertex3F(05, 35, 0)
                glVertex3F(10, 0, 0)
                glVertex3F(35, -35, 0)
                glVerTex3f(-35, -35, 0)
              glEnd
              glPopMatrix
              
              SwapBuffers(GfxDc)
              glClear(ClearClr)
              
              glFlush
              
              glFrontFace(%GL_CCW)
              glDisable(%GL_CULL_FACE)
              glDisable(%GL_DEPTH_TEST)
              glPolygonMode(%GL_FRONT_AND_BACK, %GL_FILL)
              
              glFinish
              
              END SUB
              
              '------------------------------------------------------------------
              '------------------------------------------------------------------
              
              SUB WindowToProjection(X AS DOUBLE, Y AS DOUBLE, Z AS DOUBLE)
              
              '============================================================
              ' Since the orthographic coordinate system does not reflect
              ' the window coordinate system, the window coordinate system
              ' is translated to the ortho system by gluUnProject().
              '
              ' That OpenGL function uses the window values and the values
              ' stored in the viewport matrix, the modle matrix and the
              ' projection matrix to calculate the ortho coordinates.  This
              ' routine can also be used to calculate the perspective view
              ' coordinates.
              '
              ' Because OpenGL uses the various matricies for it's calculations
              ' we have to get those matricies before calling gluUnProject().
              ' That's what the various forms of glGet...() do.  Along with
              ' our window coordinates we pass those matricies to gluUnProject()
              ' and it returns the OGL coordinates in the last three parameters:
              ' WinX, WinY, WinZ.
              '============================================================
              
              LOCAL WinViewport()   AS LONG
              LOCAL ModleMatrix()   AS DOUBLE
              LOCAL ProjectMatrix() AS DOUBLE
              
              LOCAL WinX AS DOUBLE
              LOCAL WinY AS DOUBLE
              LOCAL WinZ AS DOUBLE
              
              DIM WinViewPort(0 TO 1, 0 TO 1)    '<--- 4 element array
              DIM ModleMatrix(0 TO 3, 0 TO 3)    '<--- 16 element array
              DIM ProjectMatrix(0 TO 3, 0 TO 3)
              
              glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
              glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
              glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
              
              gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
              
              X = WinX
              Y = WinY
              Z = WinZ
              
              END SUB
              
              '--------------------------------------------------------
              '--------------------------------------------------------
              
              CALLBACK FUNCTION Mouse_SubCB
              
              LOCAL Hndl      AS DWORD
              LOCAL OrigProc  AS DWORD
              LOCAL Gfx_Hndl  AS DWORD
              
              Hndl = CBHNDL
              Gfx_Hndl = GetDlgCtrlId(Hndl)
              OrigProc = GetParent(Hndl)
              CONTROL GET USER OrigProc, Gfx_Hndl, 1 TO OrigProc
              IF OrigProc = 0 THEN EXIT FUNCTION
              
              SELECT CASE CBMSG
                CASE IS %WM_LBUTTONDOWN
                  tMouse.LbDown = 1
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_LBUTTONUP
                  tMouse.LbClk = 1
                  tMouse.LbDown = 0
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_RBUTTONDOWN
                  tMouse.RbDown = 1
                  tMouse.LbDown = 0
                  FUNCTION = 1
                  EXIT FUNCTION
              
                CASE IS %WM_RBUTTONUP
                  tMouse.RbClk = 1
                  tMouse.RbDown = 0
                  FUNCTION = 1
                  EXIT FUNCTION
              
              END SELECT
              
              FUNCTION = CallWindowProc(OrigProc, Hndl, CBMSG, CBWPARAM, CBLPARAM)
              END FUNCTION
              
              '--------------------------------------------------
              '--------------------------------------------------
              FUNCTION Az(BYVAL X1 AS SINGLE, BYVAL Y1 AS SINGLE, _
                          BYVAL X2 AS SINGLE, BYVAL Y2 AS SINGLE) AS SINGLE
              
              LOCAL Deg AS SINGLE
              LOCAL X   AS SINGLE
              LOCAL Y   AS SINGLE
              
              Deg! = 180 / (4 * ATN(1))
              X! = X2 - X1
              Y! = Y2 - Y1
              
              SELECT CASE Y!
                CASE IS < 0.0!
                  Az! = -ATN(X! / Y!) * Deg!
                  IF X! < 0.0! THEN Az! = 360.0! - ATN(X! / Y!) * Deg!
              
                CASE IS > 0.0!
                  Az! = 180.0! - ATN(X! / Y!) * Deg!
              
                CASE IS 0.0!
                  IF X! > 0.0! THEN Az! = 90.0!
                  IF X! < 0.0! THEN Az! = 270.0!
              END SELECT
              
              END FUNCTION
              
              '--------------------------------------------------------------------
              '--------------------------------------------------------------------
              
              CALLBACK FUNCTION ObjMnu_CB()
              
              
              IF CBMSG = %WM_COMMAND THEN
                IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
              
                  SELECT CASE CBCTL
                    CASE %MNU_WINDING
                      IF tFlags.Winding = 1 THEN
                        tFlags.Winding = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.Winding = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                    CASE %MNU_CULL_SURF
                      IF tFlags.Surf = 1 THEN
                        tFlags.Surf= 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.Surf = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                    CASE %MNU_DEPTH_TEST
                      IF tFlags.Test = 1 THEN
                        tFlags.Test = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_UNCHECKED OR %MF_ENABLED
                      ELSE
                        tFlags.Test = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_CHECKED OR %MF_ENABLED
                      END IF
              
                    CASE %MNU_BACKSIDE
                      IF tFlags.Back THEN
                        tFlags.Back = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.Back = 1
                      tFlags.Front = 0
                      tFlags.Both = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_FRONTSIDE
                      IF tFlags.Front THEN
                        tFlags.Front = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.Back = 0
                      tFlags.Front = 1
                      tFlags.Both = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_BOTH
                      IF tFlags.Both THEN
                        tFlags.Both = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.Back = 0
                      tFlags.Front = 0
                      tFlags.Both = 1
                      MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_CHECKED OR %MF_ENABLED
              
                    CASE %MNU_ROTATEX
                      IF tFlags.RotX THEN
                        tFlags.RotX = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.RotX = 1
                      tFlags.RotY = 0
                      tFlags.RotZ = 0
                      tFlags.RotA = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_ROTATEY
                      IF tFlags.RotY THEN
                        tFlags.RotY = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.RotY = 1
                      tFlags.RotX = 0
                      tFlags.RotZ = 0
                      tFlags.RotA = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_ROTATEZ
                      IF tFlags.RotZ THEN
                        tFlags.RotZ = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.RotZ = 1
                      tFlags.RotX = 0
                      tFlags.RotY = 0
                      tFlags.RotA = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_CHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
              
                    CASE %MNU_ROTATEALL
                      IF tFlags.RotA THEN
                        tFlags.RotA = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                        EXIT SELECT
                      END IF
                      tFlags.RotA = 1
                      tFlags.RotX = 0
                      tFlags.RotY = 0
                      tFlags.RotZ = 0
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                      MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_CHECKED OR %MF_ENABLED
              
                    CASE %MNU_EXAMPLES
                      tFlags.Examples = 1
                      CALL RunOgl(CBHNDL)
                      tFlags.Examples = 0
              
                  END SELECT
                END IF
              END IF
              END FUNCTION
              
              '---------------------------------------------------------------
              '---------------------------------------------------------------
              
              SUB Examples(BYVAL GfxHndl AS DWORD, BYVAL DlgHndl AS DWORD)
              
              LOCAL Cx      AS LONG
              LOCAL Cy      AS LONG
              LOCAL X       AS LONG
              LOCAL Y       AS LONG
              LOCAL Wide    AS LONG
              LOCAL High    AS LONG
              LOCAL TxtWide AS LONG
              
              LOCAL Txt AS STRING
              
              CONTROL GET CLIENT DlgHndl, %GFX_WIN TO Wide, High
              
              Txt$ = "Valid Polygons"
              Cx = Wide \ 2
              Cy = High \ 2
              
              GRAPHIC ATTACH GfxHndl, 0
              GRAPHIC CLEAR
              
              GRAPHIC TEXT SIZE Txt$ TO TxtWide, Y
              GRAPHIC SET POS(Cx - TxtWide \ 2, 0)
              GRAPHIC PRINT Txt$
              
              X = 40
              Y = Y + 10
              
              GRAPHIC LINE (X, Y) - (X + 15, Y + 15), %YELLOW
              GRAPHIC LINE (X + 15, Y + 15) - (X - 15, Y + 15), %YELLOW
              GRAPHIC LINE (X - 15, Y + 15) - (X, Y), %YELLOW
              GRAPHIC PAINT (X, Y + 2), %YELLOW
              
              X = 70
              
              GRAPHIC LINE (X, Y) - (X + 15, Y), %RED
              GRAPHIC LINE (X + 15, Y) - (X + 15, Y + 15), %RED
              GRAPHIC LINE (X + 15, Y + 15) - (X, Y + 15), %RED
              GRAPHIC LINE (X, Y + 15) - (X, Y), %RED
              GRAPHIC PAINT (X + 1, Y + 1), %RED
              
              X = 100
              
              GRAPHIC LINE (X, Y) - (X + 15, Y), %BLUE
              GRAPHIC LINE (X + 15, Y) - (X + 30, Y + 10), %BLUE
              GRAPHIC LINE (X + 30, Y + 10) - (X + 20, Y + 15), %BLUE
              GRAPHIC LINE (X + 20, Y + 15) - (X, Y + 15), %BLUE
              GRAPHIC LINE (X, Y + 15) - (X, Y), %BLUE
              GRAPHIC PAINT (X + 1, Y + 1), %BLUE
              
              Txt$ = "Invalid Polygons"
              
              GRAPHIC TEXT SIZE Txt$ TO TxtWide, Y
              GRAPHIC SET POS(Cx - TxtWide \ 2, Cy - Y \ 2)
              GRAPHIC PRINT Txt$
              
              X = 50
              Y = Cy + 10
              
              GRAPHIC LINE (X, Y) - (X + 20, Y + 20), %RED
              GRAPHIC LINE (X + 20, Y + 20) - (X, Y + 20), %RED
              GRAPHIC LINE (X, Y + 20) - (X + 20, Y), %RED
              GRAPHIC LINE (X + 20, Y) - (X, Y), %RED
              GRAPHIC PAINT (X + 10, Y + 1), RGB(75, 128, 200), %RED
              GRAPHIC PAINT (X + 10, Y + 15), RGB(100, 160, 240), %RED
              
              X = 100
              
              GRAPHIC LINE (X, Y) - (X + 10, Y + 10), %BLUE
              GRAPHIC LINE (X + 10, Y + 10) - (X + 20, Y), %BLUE
              GRAPHIC LINE (X + 20, Y) - (X + 30, Y + 20), %BLUE
              GRAPHIC LINE (X + 30, Y + 20) - (X + 10, Y + 15), %BLUE
              GRAPHIC LINE (X + 10, Y + 15) - (X, Y + 15), %BLUE
              GRAPHIC LINE (X, Y + 15) - (X - 5, Y + 20), %BLUE
              GRAPHIC LINE(X - 5, Y + 20) - (X, Y), %BLUE
              GRAPHIC PAINT (X + 2, Y + 2), %GREEN, %BLUE
              
              GRAPHIC DETACH
              END SUB
              Walt Decker

              Comment


              • #8
                &quot;Z&quot; Factor

                Using a "Z" factor with a polygon can produce some interesting
                results when the polygon is rotated. In effect if throws part of the
                polygon into a second plane, producing bends, folds, and curves.

                The following code example demonstrates the effect of the "Z" factor on both valid and invalid polygons.

                Code:
                '======================================================================
                '                           ADDING "Z" FACTOR TO POLYGONS
                '----------------------------------------------------------------------
                '   Using a "Z" factor with a polygon can produce some interesting
                ' results when the polygon is rotated.  In effect if throws part of the
                ' polygon into a second plane, producing bends, folds, and curves.
                '----------------------------------------------------------------------
                '
                '=======================================================================
                '                            OPENGL FUNCTIONS USED
                '=======================================================================
                ' glViewport()
                ' glMatrixMode()
                ' glLoadIdentity
                ' glOrtho()
                ' glclear()
                ' glPushMatrix
                ' glTranslatef()
                ' glColor3Ub()
                ' glBegin()
                ' glEnd
                ' glVertex3F()
                ' glRotateF()
                ' glPopMatrix
                ' glEnable()
                ' glDisable()
                ' glFlush
                ' glFinish
                '=========================================================================
                '                            WINDOWS FUNCTIONS USED
                '=========================================================================
                ' GetDc
                ' ReleaseDc
                ' ChoosePixelFormat
                ' SetWindowLong
                ' SetPixelFormat
                ' wglCreateContext
                ' wglMakeCurrent
                ' wglDeleteContext
                ' SetWindowLong
                '=========================================================================
                
                #COMPILE EXE
                
                DEFLNG A - Z
                
                #INCLUDE "WIN32API.INC"
                #INCLUDE "gl.inc"
                #INCLUDE "glu.inc"
                
                TYPE MenuFlag_STRUCT
                  Winding   AS BIT * 1 IN BYTE
                  Surf      AS BIT * 1
                  Test      AS BIT * 1
                  Back      AS BIT * 1
                  Front     AS BIT * 1
                  Both      AS BIT * 1
                  Examples  AS BIT * 1
                  AddZ      AS BIT * 1
                END TYPE
                
                TYPE Rotate_STRUCT
                  RotX  AS BIT * 1 IN BYTE
                  RotY  AS BIT * 1
                  RotZ  AS BIT * 1
                  RotA  AS BIT * 1
                END TYPE
                
                TYPE OglFlag_STRUCT
                  EndProg     AS BIT * 1 IN BYTE
                  MouseClk    AS BIT * 1
                  OglBtnDead  AS BIT * 1
                  RunGlDemo   AS BIT * 1
                  MenuFlag_STRUCT
                  Rotate_STRUCT
                END TYPE
                
                TYPE Button_STRUCT
                  LbDown AS BIT * 1 IN BYTE
                  LbClk  AS BIT * 1
                  RbDown AS BIT * 1
                  RbClk  AS BIT * 1
                END TYPE
                
                TYPE Single2_STRUCT
                  Mx  AS SINGLE
                  My  AS SINGLE
                END TYPE
                
                TYPE Mouse_STRUCT
                  Single2_STRUCT
                  Button_STRUCT
                END TYPE
                
                
                MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                          '   correctly while in 2dimensional mode
                
                %GFX_WIN     =    5
                %BTN_END     =    6
                %BTN_OGL     =    7
                
                %MNU_WINDING    = 50
                %MNU_CULL_SURF  = 51
                %MNU_DEPTH_TEST = 52
                %MNU_BACKSIDE   = 53
                %MNU_FRONTSIDE  = 54
                %MNU_BOTH       = 55
                %MNU_ROTATE     = 56
                %MNU_ROTATEX    = 57
                %MNU_ROTATEY    = 58
                %MNU_ROTATEZ    = 59
                %MNU_ROTATEALL  = 60
                %MNU_EXAMPLES   = 61
                %MNU_ADDZ       = 62
                
                %OGL_ERROR   = %WM_USER + 500
                
                GLOBAL tFlags AS OglFlag_STRUCT
                GLOBAL tMouse AS Mouse_STRUCT
                GLOBAL MnuHndl AS DWORD
                
                DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
                DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                            GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                
                DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                        BYVAL GfxHndl AS DWORD)
                
                DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
                
                DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                
                
                DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                            tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                
                
                DECLARE FUNCTION PBMAIN() AS LONG
                DECLARE CALLBACK FUNCTION Main_CB()
                
                FUNCTION PBMAIN()
                
                LOCAL hDlg  AS DWORD
                LOCAL Txt AS STRING
                
                DIALOG NEW 0, "Exploring Ogl - Adding Z Factor", , , 201, 131, _
                                        %WS_POPUP OR %WS_BORDER _
                                        OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                        %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                        %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                        %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                
                CONTROL ADD GRAPHIC, hDlg, %GFX_WIN, "", 5, 5, 190, 80, _
                                                         %SS_SUNKEN OR %SS_NOTIFY OR %WS_CHILD OR _
                                                        %WS_VISIBLE
                
                CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
                  OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                  %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                  %WS_EX_LTRREADING
                
                CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
                  %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                  OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                  %WS_EX_LTRREADING
                
                DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
                
                MENU NEW BAR TO MnuHndl
                MENU NEW POPUP TO ChildHndl
                MENU ADD POPUP, MnuHndl, "OGL Image Parameters", ChildHndl, %MF_ENABLED
                
                  MENU ADD STRING, ChildHndl, "Change Winding", %MNU_WINDING, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                
                  MENU ADD STRING, ChildHndl, "Remove Hidden Surfaces", %MNU_CULL_SURF, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl, "Depth Test", %MNU_DEPTH_TEST, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl, "Lines On Back Side Only", %MNU_BACKSIDE, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl, "Lines On Front Side Only", %MNU_FRONTSIDE, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl, "Lines On Both Sides", %MNU_BOTH, %MF_ENABLED OR %MF_CHECKED, _
                                               CALL ObjMnu_CB
                  MENU ADD STRING, ChildHndl, "Add Z Factor", %MNU_ADDZ, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                  MENU NEW POPUP TO ChildHndl_2
                  MENU ADD POPUP, ChildHndl, "Rotate", ChildHndl_2, %MF_ENABLED
                    MENU ADD STRING, ChildHndl_2, "Around X Axsis", %MNU_ROTATEX, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl_2, "Around Y Axsis", %MNU_ROTATEY, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl_2, "Around Z Axsis", %MNU_ROTATEZ, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl_2, "Around All", %MNU_ROTATEALL, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                MENU ADD STRING, MnuHndl, "Examples", %MNU_EXAMPLES, %MF_ENABLED, _
                                               CALL ObjMnu_CB
                
                MENU ATTACH MnuHndl, hDlg
                
                DIALOG SHOW MODAL hDlg, CALL Main_CB
                
                END FUNCTION
                
                '------------------------------------------------------------
                '------------------------------------------------------------
                
                CALLBACK FUNCTION Main_CB()
                
                LOCAL lParam AS LONG
                LOCAL wParam AS LONG
                
                SELECT CASE AS LONG CBMSG
                
                  wParam = CBWPARAM
                  CASE %WM_INITDIALOG
                    tFlags.Both = 1
                  CASE %WM_COMMAND
                    wParam = CBCTLMSG
                    SELECT CASE AS LONG wParam
                      CASE %BN_CLICKED, %STN_CLICKED, 1
                        SELECT CASE AS LONG CBCTL
                          CASE %GFX_WIN
                
                          CASE %BTN_END
                            tFlags.EndProg = 1
                            CALL RunOgl(CBHNDL)
                            DIALOG END CBHNDL
                            FUNCTION = 1
                            EXIT FUNCTION
                
                          CASE %BTN_OGL
                            CONTROL DISABLE CBHNDL, %BTN_OGL
                            tFlags.OglBtnDead = 1
                            tFlags.RunGlDemo = 1
                            CALL RunOgl(CBHNDL)
                            FUNCTION = 1
                            EXIT FUNCTION
                
                        END SELECT
                    END SELECT
                
                  CASE %WM_DESTROY
                    IF tFlags.EndProg THEN EXIT SELECT
                    tFlags.EndProg = 1
                    CALL RunOgl(CBHNDL)
                
                  CASE %OGL_ERROR
                    SELECT CASE wParam
                      CASE 1
                        MSGBOX "Could not find matching pixel format"
                      CASE 2
                        MSGBOX "Could not set selected pixel format"
                      CASE 3
                        MSGBOX "Could not create rendering context"
                      CASE 4
                        MSGBOX "Could not make rendering context current.  Defined window may not" _
                               + " support it"
                    END SELECT
                    DIALOG END CBHNDL
                END SELECT
                
                END FUNCTION
                
                '------------------------------------------------------------
                '------------------------------------------------------------
                
                SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                
                '==============================================================
                ' This is the 1st step in setting up windows for OpenGl support
                ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
                ' graphics
                '==============================================================
                
                pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
                pfd.nversion = 1
                pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
                pfd.dwlayermask = %PFD_MAIN_PLANE
                pfd.ipixeltype = %PFD_TYPE_RGBA
                pfd.ccolorbits = 24
                pfd.cdepthbits = 24
                pfd.caccumbits = 0
                pfd.cstencilbits = 0
                
                END SUB
                
                '---------------------------------------------------------------
                '---------------------------------------------------------------
                
                SUB RunOgl(BYVAL Hndl AS DWORD)
                
                STATIC Wide  AS LONG
                STATIC High  AS LONG
                
                STATIC GfxDC     AS DWORD
                STATIC OglRc     AS DWORD
                STATIC GfxHndl   AS DWORD
                
                LOCAL Img() AS BYTE
                
                LOCAL X     AS DOUBLE
                LOCAL Y     AS DOUBLE
                LOCAL Z     AS DOUBLE
                
                LOCAL Azi AS LONG
                LOCAL Lazi AS LONG
                
                LOCAL HalfWide AS LONG
                LOCAL HalfHigh AS LONG
                
                LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
                
                IF tFlags.Examples THEN
                  IF ISTRUE(GfxDc) THEN
                    CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                    GfxDc = 0
                    OglRc = 0
                  ELSE
                    CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                    ReleaseDc(GfxHndl, GfxDc)
                    GfxDc = 0
                  END IF
                  CALL Examples(GfxHndl, Hndl)
                  EXIT SUB
                END IF
                
                IF ISFALSE(GfxDc) THEN
                  IF tFlags.EndProg THEN EXIT SUB
                
                  CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                  CALL OglPixFormat(tPixFmt)
                
                  OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
                
                  IF OglRc = 0 THEN EXIT SUB
                
                  CALL SetOglWindow(Wide, High, 100)
                
                END IF
                
                IF tFlags.EndProg THEN
                  CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                  EXIT SUB
                END IF
                
                IF tFlags.RunGlDemo THEN
                  HalfWide = Wide \ 2
                  HalfHigh = High \ 2
                  CALL glRunDemo(Azi, GfxDc)
                  SLEEP 50
                  Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, CODEPTR(Mouse_SubCB))
                  CONTROL SET USER Hndl, %GFX_WIN, 1, Proc
                  DO
                    DIALOG DOEVENTS
                
                    IF tFlags.EndProg THEN
                      CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                      EXIT DO
                    END IF
                    IF tMouse.LbDown = 0 THEN ITERATE DO
                
                    DO
                      DIALOG DOEVENTS
                      CALL Mouse(GfxHndl, 0)
                      Azi = Az(HalfWide, HalfHigh, tMouse.Mx, tMouse.My)
                      CALL glRunDemo(Azi, GfxDc)
                    LOOP UNTIL tMouse.LbDown = 0 OR tFlags.EndProg = 1
                  LOOP
                END IF
                
                SetWindowLong(GfxHndl, %GWL_WNDPROC, Proc)
                CONTROL SET USER Hndl, %GFX_WIN, 1, 0
                
                END SUB
                
                '----------------------------------------------------------------
                '----------------------------------------------------------------
                
                FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                    tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                
                '================================================================
                '  This is the second step for OpenGL support
                '  ChoosePixelFormat selects a pixel format that matches that
                '  described in the PIXELFORMATDESCRIPTOR structure.
                '
                '  Each step in the setup is quried because not all windows support
                '  OpenGL rendering
                '================================================================
                
                LOCAL PixFormat AS DWORD
                LOCAL OglRc     AS DWORD
                
                LOCAL T AS LONG
                
                PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
                
                IF ISFALSE (PixFormat) THEN
                  DIALOG POST Hndl, %OGL_ERROR, 1, 0
                  EXIT FUNCTION
                END IF
                
                t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
                
                IF ISFALSE(t) THEN
                  DIALOG POST Hndl, %OGL_ERROR, 2, 0
                  EXIT FUNCTION
                END IF
                
                OglRc = wglCreateContext(GfxDc)
                
                IF ISFALSE(OglRc) THEN
                  DIALOG POST Hndl, %OGL_ERROR, 3, 0
                  EXIT FUNCTION
                END IF
                
                t = wglMakeCurrent(GfxDc, OglRc)
                
                IF ISFALSE(t) THEN
                  DIALOG POST Hndl, %OGL_ERROR, 4, 0
                  EXIT FUNCTION
                END IF
                
                SetOglPipe = OglRc
                END FUNCTION
                
                '----------------------------------------------------------------
                '----------------------------------------------------------------
                
                SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                 BYVAL OrthoRange AS LONG)
                
                LOCAL ClearClr AS DWORD
                
                LOCAL Aspect AS SINGLE
                LOCAL Xmin   AS SINGLE
                LOCAL Ymin   AS SINGLE
                LOCAL Xmax   AS SINGLE
                LOCAL Ymax   AS SINGLE
                LOCAL Zmin   AS SINGLE
                LOCAL Zmax   AS SINGLE
                
                '=================================================================
                ' This defines the graphics environment.
                ' Getting this correct is crucial to using OpenGL.
                '
                ' In previous examples the orthographic projection was set to the
                ' window coordinates.  This now changes the projection coordinates
                ' to something other than the window coordinates.
                '=================================================================
                
                ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                           %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                
                IF Wide <= High THEN
                  Aspect! = High / Wide
                ELSE
                  Aspect! = Wide / High
                END IF
                
                IF Wide <= High THEN
                  Xmin! = -OrthoRange / 2
                  Xmax! = OrthoRange  / 2
                  Ymin! = (-OrthoRange / 2) * Aspect!
                  Ymax! = (OrthoRange / 2) * Aspect!
                ELSE
                  Xmin! = (-OrthoRange / 2) * Aspect!
                  Xmax! = (OrthoRange / 2) * Aspect!
                  Ymin! = (-OrthoRange / 2)
                  Ymax! = (OrthoRange  / 2)
                END IF
                
                Zmin! = -OrthoRange / 2
                Zmax! = OrthoRange
                
                glViewport(0, 0, Wide, High)
                glMatrixMode(%GL_PROJECTION)
                glLoadIdentity
                glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
                glMatrixMode(%GL_MODELVIEW)
                glLoadIdentity
                glClear(ClearClr)
                
                END SUB
                
                
                '----------------------------------------------------------------
                '----------------------------------------------------------------
                
                SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
                
                wglMakeCurrent(0, 0)
                wglDeleteContext(OglRc)
                ReleaseDc(GfxHndl,GfxDc)
                
                END SUB
                
                '----------------------------------------------------------------
                '----------------------------------------------------------------
                
                SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                    GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                
                CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
                CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
                DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
                
                GfxDc = GetDc(GfxHndl)
                
                END SUB
                
                '-----------------------------------------------------------------
                '-----------------------------------------------------------------
                
                SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                
                LOCAL tPoint AS POINT
                
                GetCursorPos(tPoint)
                ScreenToClient(GfxHndl, tPoint)
                
                tMouse.Mx = tPoint.X
                tMouse.My = tPoint.Y
                
                END SUB
                
                '-------------------------------------------------------------------
                '-------------------------------------------------------------------
                
                SUB glRunDemo(BYVAL Azi AS LONG , BYVAL GfxDc AS DWORD)
                
                '===================================================================
                ' Each of the polygons has a local origin as defined by TranslateF()
                ' or a designated offset from the orthographic projection origin.
                ' When they are rotated they each rotate around their local origin.
                ' Notice that the middle polygon rotates around a point that is not
                ' the center when "rotate around z" is enabled.
                '===================================================================
                
                LOCAL ClearClr AS DWORD
                
                LOCAL AngStep   AS LONG
                LOCAL ValidZ    AS LONG
                LOCAL InvalidZ  AS LONG
                
                LOCAL Pi    AS SINGLE
                LOCAL Rad   AS SINGLE
                LOCAL Z     AS SINGLE
                
                ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                           %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                
                Pi! = 4 * ATN(1)
                Rad! = Pi! / 180
                AngStep = 8
                AngStep = 360 \ AngStep
                
                IF tFlags.Winding THEN
                  glFrontFace(%GL_CW)
                END IF
                
                IF tFlags.Surf THEN
                  glEnable(%GL_CULL_FACE)
                END IF
                
                IF tFlags.Test THEN
                  glEnable(%GL_DEPTH_TEST)
                END IF
                
                IF tFlags.Back = 1 THEN
                  glPolygonMode(%GL_BACK, %GL_LINE)
                END IF
                
                IF tFlags.Front = 1 THEN
                  glPolygonMode(%GL_FRONT, %GL_LINE)
                END IF
                
                IF tFlags.Both = 1 THEN
                  glPolygonMode(%GL_FRONT_AND_BACK, %GL_LINE)
                END IF
                
                IF tFlags.AddZ THEN
                  ValidZ = -25
                  InvalidZ = -35
                END IF
                
                '===========================================================
                ' This is a valid polygon.  It can be normalize and is convex.
                ' Ogl has no problem rendering it correctly no matter what is
                ' done to it
                '===========================================================
                
                glPushMatrix
                glTranslateF(75, 0, 0)
                glColor3Ub(128, 255, 200)
                
                IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
                IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
                IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
                IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
                
                glBegin(%GL_POLYGON)
                FOR I = 0 TO 360 - AngStep STEP AngStep
                  X = 30 * SIN(I * Rad!)
                  Y = 30 * COS(I * Rad!)
                  glVertex3F(X, Y, ValidZ)
                  IF tFlags.AddZ THEN
                    IF I >= 90 THEN
                      ValidZ = ValidZ + 10
                    END IF
                  END IF
                NEXT I
                glEnd
                glPopMatrix
                
                '======================================================
                ' This is an invalid polygon because it resides in two
                ' planes, i.e., the verticies cross; therefore it cannot
                ' be normalized and Ogl has problems rendering it correctly.
                '======================================================
                
                glPushMatrix
                glTranslateF(25, 0, 0)
                glColor3Ub(255, 128, 200)
                
                IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
                IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
                IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
                IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
                
                glBegin(%GL_QUADS)
                
                IF tFlags.AddZ THEN
                  glVertex3F(-35, 35, InvalidZ)
                  glVertex3F(05, -35, 0)
                  glVertex3F(-35, -35, 0)
                  glVertex3F(05, 35, InvlaidZ + 50)
                ELSE
                  glVertex3F(-35, 35, 0)
                  glVertex3F(05, -35, 0)
                  glVertex3F(-35, -35, 0)
                  glVertex3F(05, 35, 0)
                END IF
                
                glEnd
                glPopMatrix
                
                '========================================================
                ' This is an invalid polygon.  Although no verticies cross,
                ' it is not convex; therefore Ogl has problems rendering it
                ' correctly.
                '========================================================
                
                glPushMatrix
                glTranslateF(-65, 0, 0)
                glColor3Ub(126, 0, 200)
                
                IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
                IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
                IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
                IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
                
                glBegin(%GL_POLYGON)
                
                IF tFlags.AddZ THEN
                  glVertex3F(-35, 35, InvalidZ)
                  glVertex3F(-15, 15, 0)
                  glVertex3F(05, 35, InvalidZ - 10)
                  glVertex3F(10, 0, InvalidZ + 50)
                  glVertex3F(35, -35, 0)
                  glVerTex3f(-35, -35, InvalidZ - 30)
                ELSE
                  glVertex3F(-35, 35, 0)
                  glVertex3F(-15, 15, 0)
                  glVertex3F(05, 35, 0)
                  glVertex3F(10, 0, 0)
                  glVertex3F(35, -35, 0)
                  glVerTex3f(-35, -35, 0)
                END IF
                
                glEnd
                glPopMatrix
                
                SwapBuffers(GfxDc)
                glClear(ClearClr)
                
                glFlush
                
                glFrontFace(%GL_CCW)
                glDisable(%GL_CULL_FACE)
                glDisable(%GL_DEPTH_TEST)
                glPolygonMode(%GL_FRONT_AND_BACK, %GL_FILL)
                
                glFinish
                
                END SUB
                
                '------------------------------------------------------------------
                '------------------------------------------------------------------
                
                CALLBACK FUNCTION Mouse_SubCB
                
                LOCAL Hndl      AS DWORD
                LOCAL OrigProc  AS DWORD
                LOCAL Gfx_Hndl  AS DWORD
                
                Hndl = CBHNDL
                Gfx_Hndl = GetDlgCtrlId(Hndl)
                OrigProc = GetParent(Hndl)
                CONTROL GET USER OrigProc, Gfx_Hndl, 1 TO OrigProc
                IF OrigProc = 0 THEN EXIT FUNCTION
                
                SELECT CASE CBMSG
                  CASE IS %WM_LBUTTONDOWN
                    tMouse.LbDown = 1
                    FUNCTION = 1
                    EXIT FUNCTION
                
                  CASE IS %WM_LBUTTONUP
                    tMouse.LbClk = 1
                    tMouse.LbDown = 0
                    FUNCTION = 1
                    EXIT FUNCTION
                
                  CASE IS %WM_RBUTTONDOWN
                    tMouse.RbDown = 1
                    tMouse.LbDown = 0
                    FUNCTION = 1
                    EXIT FUNCTION
                
                  CASE IS %WM_RBUTTONUP
                    tMouse.RbClk = 1
                    tMouse.RbDown = 0
                    FUNCTION = 1
                    EXIT FUNCTION
                
                END SELECT
                
                FUNCTION = CallWindowProc(OrigProc, Hndl, CBMSG, CBWPARAM, CBLPARAM)
                END FUNCTION
                
                '--------------------------------------------------
                '--------------------------------------------------
                FUNCTION Az(BYVAL X1 AS SINGLE, BYVAL Y1 AS SINGLE, _
                            BYVAL X2 AS SINGLE, BYVAL Y2 AS SINGLE) AS SINGLE
                
                LOCAL Deg AS SINGLE
                LOCAL X   AS SINGLE
                LOCAL Y   AS SINGLE
                
                Deg! = 180 / (4 * ATN(1))
                X! = X2 - X1
                Y! = Y2 - Y1
                
                SELECT CASE Y!
                  CASE IS < 0.0!
                    Az! = -ATN(X! / Y!) * Deg!
                    IF X! < 0.0! THEN Az! = 360.0! - ATN(X! / Y!) * Deg!
                
                  CASE IS > 0.0!
                    Az! = 180.0! - ATN(X! / Y!) * Deg!
                
                  CASE IS 0.0!
                    IF X! > 0.0! THEN Az! = 90.0!
                    IF X! < 0.0! THEN Az! = 270.0!
                END SELECT
                
                END FUNCTION
                
                '---------------------------------------------------------
                '---------------------------------------------------------
                
                SUB RegWindow(Nam AS ASCIIZ, BYVAL Styl AS DWORD, BYVAL Code_Ptr AS DWORD, _
                                         BYVAL Inst AS DWORD, BYVAL BkBrush AS DWORD, RegOk AS BYTE)
                
                LOCAL tWindow AS WNDCLASSEX
                
                tWindow.cbSize        = SIZEOF(tWindow)
                tWindow.style         = Styl
                tWindow.lpfnWndProc   = Code_Ptr
                tWindow.cbClsExtra    = 0
                tWindow.cbWndExtra    = 32
                tWindow.hInstance     = Inst
                tWindow.hIcon         = %NULL
                tWindow.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                
                IF BkBrush = 0 THEN
                  tWindow.hbrBackground = 0
                ELSE
                  tWindow.hbrBackground = GetStockObject(BkBrush)
                END IF
                
                tWindow.lpszMenuName  = %NULL
                tWindow.lpszClassName = VARPTR(Nam$)
                tWindow.hIconSm       = %NULL
                
                Styl = RegisterClassEx(tWindow)
                
                IF Styl THEN RegOk = 1
                
                END SUB
                
                CALLBACK FUNCTION ObjMnu_CB()
                
                
                IF CBMSG = %WM_COMMAND THEN
                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                
                    SELECT CASE CBCTL
                      CASE %MNU_WINDING
                        IF tFlags.Winding = 1 THEN
                          tFlags.Winding = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_UNCHECKED OR %MF_ENABLED
                        ELSE
                          tFlags.Winding = 1
                          MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_CHECKED OR %MF_ENABLED
                        END IF
                
                      CASE %MNU_CULL_SURF
                        IF tFlags.Surf = 1 THEN
                          tFlags.Surf= 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_UNCHECKED OR %MF_ENABLED
                        ELSE
                          tFlags.Surf = 1
                          MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_CHECKED OR %MF_ENABLED
                        END IF
                
                      CASE %MNU_DEPTH_TEST
                        IF tFlags.Test = 1 THEN
                          tFlags.Test = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_UNCHECKED OR %MF_ENABLED
                        ELSE
                          tFlags.Test = 1
                          MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_CHECKED OR %MF_ENABLED
                        END IF
                
                      CASE %MNU_BACKSIDE
                        IF tFlags.Back THEN
                          tFlags.Back = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.Back = 1
                        tFlags.Front = 0
                        tFlags.Both = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_CHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                
                      CASE %MNU_FRONTSIDE
                        IF tFlags.Front THEN
                          tFlags.Front = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.Back = 0
                        tFlags.Front = 1
                        tFlags.Both = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_CHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                
                      CASE %MNU_BOTH
                        IF tFlags.Both THEN
                          tFlags.Both = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.Back = 0
                        tFlags.Front = 0
                        tFlags.Both = 1
                        MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_CHECKED OR %MF_ENABLED
                
                      CASE %MNU_ADDZ
                        IF tFlags.AddZ THEN
                          MENU SET STATE MnuHndl, BYCMD %MNU_ADDZ, %MF_UNCHECKED OR %MF_ENABLED
                          tFlags.AddZ = 0
                          EXIT SELECT
                        END IF
                          MENU SET STATE MnuHndl, BYCMD %MNU_ADDZ, %MF_CHECKED OR %MF_ENABLED
                          tFlags.AddZ = 1
                
                      CASE %MNU_ROTATEX
                        IF tFlags.RotX THEN
                          tFlags.RotX = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.RotX = 1
                        tFlags.RotY = 0
                        tFlags.RotZ = 0
                        tFlags.RotA = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_CHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                
                      CASE %MNU_ROTATEY
                        IF tFlags.RotY THEN
                          tFlags.RotY = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.RotY = 1
                        tFlags.RotX = 0
                        tFlags.RotZ = 0
                        tFlags.RotA = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_CHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                
                      CASE %MNU_ROTATEZ
                        IF tFlags.RotZ THEN
                          tFlags.RotZ = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.RotZ = 1
                        tFlags.RotX = 0
                        tFlags.RotY = 0
                        tFlags.RotA = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_CHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                
                      CASE %MNU_ROTATEALL
                        IF tFlags.RotA THEN
                          tFlags.RotA = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                          EXIT SELECT
                        END IF
                        tFlags.RotA = 1
                        tFlags.RotX = 0
                        tFlags.RotY = 0
                        tFlags.RotZ = 0
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                        MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_CHECKED OR %MF_ENABLED
                
                      CASE %MNU_EXAMPLES
                        tFlags.Examples = 1
                        CALL RunOgl(CBHNDL)
                        tFlags.Examples = 0
                
                    END SELECT
                  END IF
                END IF
                END FUNCTION
                
                '---------------------------------------------------------------
                '---------------------------------------------------------------
                
                SUB Examples(BYVAL GfxHndl AS DWORD, BYVAL DlgHndl AS DWORD)
                
                LOCAL Cx      AS LONG
                LOCAL Cy      AS LONG
                LOCAL X       AS LONG
                LOCAL Y       AS LONG
                LOCAL Wide    AS LONG
                LOCAL High    AS LONG
                LOCAL TxtWide AS LONG
                
                LOCAL Txt AS STRING
                
                CONTROL GET CLIENT DlgHndl, %GFX_WIN TO Wide, High
                
                Txt$ = "Valid Polygons"
                Cx = Wide \ 2
                Cy = High \ 2
                
                GRAPHIC ATTACH GfxHndl, 0
                GRAPHIC CLEAR
                
                GRAPHIC TEXT SIZE Txt$ TO TxtWide, Y
                GRAPHIC SET POS(Cx - TxtWide \ 2, 0)
                GRAPHIC PRINT Txt$
                
                X = 40
                Y = Y + 10
                
                GRAPHIC LINE (X, Y) - (X + 15, Y + 15), %YELLOW
                GRAPHIC LINE (X + 15, Y + 15) - (X - 15, Y + 15), %YELLOW
                GRAPHIC LINE (X - 15, Y + 15) - (X, Y), %YELLOW
                GRAPHIC PAINT (X, Y + 2), %YELLOW
                
                X = 70
                
                GRAPHIC LINE (X, Y) - (X + 15, Y), %RED
                GRAPHIC LINE (X + 15, Y) - (X + 15, Y + 15), %RED
                GRAPHIC LINE (X + 15, Y + 15) - (X, Y + 15), %RED
                GRAPHIC LINE (X, Y + 15) - (X, Y), %RED
                GRAPHIC PAINT (X + 1, Y + 1), %RED
                
                X = 100
                
                GRAPHIC LINE (X, Y) - (X + 15, Y), %BLUE
                GRAPHIC LINE (X + 15, Y) - (X + 30, Y + 10), %BLUE
                GRAPHIC LINE (X + 30, Y + 10) - (X + 20, Y + 15), %BLUE
                GRAPHIC LINE (X + 20, Y + 15) - (X, Y + 15), %BLUE
                GRAPHIC LINE (X, Y + 15) - (X, Y), %BLUE
                GRAPHIC PAINT (X + 1, Y + 1), %BLUE
                
                Txt$ = "Invalid Polygons"
                
                GRAPHIC TEXT SIZE Txt$ TO TxtWide, Y
                GRAPHIC SET POS(Cx - TxtWide \ 2, Cy - Y \ 2)
                GRAPHIC PRINT Txt$
                
                X = 50
                Y = Cy + 10
                
                GRAPHIC LINE (X, Y) - (X + 20, Y + 20), %RED
                GRAPHIC LINE (X + 20, Y + 20) - (X, Y + 20), %RED
                GRAPHIC LINE (X, Y + 20) - (X + 20, Y), %RED
                GRAPHIC LINE (X + 20, Y) - (X, Y), %RED
                GRAPHIC PAINT (X + 10, Y + 1), RGB(75, 128, 200), %RED
                GRAPHIC PAINT (X + 10, Y + 15), RGB(100, 160, 240), %RED
                
                X = 100
                
                GRAPHIC LINE (X, Y) - (X + 10, Y + 10), %BLUE
                GRAPHIC LINE (X + 10, Y + 10) - (X + 20, Y), %BLUE
                GRAPHIC LINE (X + 20, Y) - (X + 30, Y + 20), %BLUE
                GRAPHIC LINE (X + 30, Y + 20) - (X + 10, Y + 15), %BLUE
                GRAPHIC LINE (X + 10, Y + 15) - (X, Y + 15), %BLUE
                GRAPHIC LINE (X, Y + 15) - (X - 5, Y + 20), %BLUE
                GRAPHIC LINE(X - 5, Y + 20) - (X, Y), %BLUE
                GRAPHIC PAINT (X + 2, Y + 2), %GREEN, %BLUE
                
                GRAPHIC DETACH
                END SUB
                Walt Decker

                Comment


                • #9
                  Pinning

                  Each polygon rotates around it's local origin. However, this can
                  be changed by pinning the rotation to different XY, XZ, or YZ axis.

                  The following example demonstrates the effect of pinning valid and invalid polygons to an arbitrary axis.

                  Code:
                  '=======================================================================
                  '                           PINNING
                  '-----------------------------------------------------------------------
                  '   Each polygon rotates around it's local origin.  However, this can
                  ' be changed by pinning the rotation to different XY, XZ, or YZ axsis
                  '-----------------------------------------------------------------------
                  '
                  '=======================================================================
                  '                            OPENGL FUNCTIONS USED
                  '=======================================================================
                  ' glViewport()
                  ' glMatrixMode()
                  ' glLoadIdentity
                  ' glOrtho()
                  ' glclear()
                  ' glPushMatrix
                  ' glTranslatef()
                  ' glColor3Ub()
                  ' glBegin()
                  ' glEnd
                  ' glVertex3F()
                  ' glRotateF()
                  ' glPopMatrix
                  ' glEnable()
                  ' glDisable()
                  ' glFlush
                  ' glFinish
                  '=========================================================================
                  '                            WINDOWS FUNCTIONS USED
                  '=========================================================================
                  ' GetDc
                  ' ReleaseDc
                  ' ChoosePixelFormat
                  ' SetWindowLong
                  ' SetPixelFormat
                  ' wglCreateContext
                  ' wglMakeCurrent
                  ' wglDeleteContext
                  ' SetWindowLong
                  '=========================================================================
                  
                  #COMPILE EXE
                  
                  DEFLNG A - Z
                  
                  #INCLUDE "WIN32API.INC"
                  #INCLUDE "gl.inc"
                  #INCLUDE "glu.inc"
                  
                  TYPE MenuFlag_STRUCT
                    Winding   AS BIT * 1 IN BYTE
                    Surf      AS BIT * 1
                    Test      AS BIT * 1
                    Back      AS BIT * 1
                    Front     AS BIT * 1
                    Both      AS BIT * 1
                    Pin       AS BIT * 1
                    AddZ      AS BIT * 1
                  END TYPE
                  
                  TYPE Rotate_STRUCT
                    RotX  AS BIT * 1 IN BYTE
                    RotY  AS BIT * 1
                    RotZ  AS BIT * 1
                    RotXY AS BIT * 1
                    RotXZ AS BIT * 1
                    RotYZ AS BIT * 1
                    RotA  AS BIT * 1
                    Move  AS BIT * 1
                  END TYPE
                  
                  TYPE OglFlag_STRUCT
                    EndProg     AS BIT * 1 IN BYTE
                    MouseClk    AS BIT * 1
                    OglBtnDead  AS BIT * 1
                    RunGlDemo   AS BIT * 1
                    MenuFlag_STRUCT
                    Rotate_STRUCT
                  END TYPE
                  
                  TYPE Button_STRUCT
                    LbDown AS BIT * 1 IN BYTE
                    LbClk  AS BIT * 1
                    RbDown AS BIT * 1
                    RbClk  AS BIT * 1
                  END TYPE
                  
                  TYPE Single2_STRUCT
                    Mx  AS SINGLE
                    My  AS SINGLE
                  END TYPE
                  
                  TYPE Mouse_STRUCT
                    Single2_STRUCT
                    Button_STRUCT
                  END TYPE
                  
                  
                  MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                            '   correctly while in 2dimensional mode
                  
                  %GFX_WIN     =    5
                  %BTN_END     =    6
                  %BTN_OGL     =    7
                  
                  %MNU_WINDING    = 50
                  %MNU_CULL_SURF  = 51
                  %MNU_DEPTH_TEST = 52
                  %MNU_BACKSIDE   = 53
                  %MNU_FRONTSIDE  = 54
                  %MNU_BOTH       = 55
                  %MNU_ROTATE     = 56
                  %MNU_ROTATEX    = 57
                  %MNU_ROTATEY    = 58
                  %MNU_ROTATEZ    = 59
                  %MNU_ROTATEALL  = 60
                  %MNU_ADDZ       = 62
                  %MNU_ROTATEXY   = 63
                  %MNU_ROTATEXZ   = 64
                  %MNU_ROTATEYZ   = 65
                  %MNU_MOVE       = 66
                  
                  %OGL_ERROR   = %WM_USER + 500
                  
                  GLOBAL tFlags AS OglFlag_STRUCT
                  GLOBAL tMouse AS Mouse_STRUCT
                  GLOBAL MnuHndl AS DWORD
                  
                  DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                  DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
                  DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                              GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                  
                  DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                          BYVAL GfxHndl AS DWORD)
                  
                  DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
                  
                  DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                  
                  
                  DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                              tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                  
                  
                  DECLARE FUNCTION PBMAIN() AS LONG
                  DECLARE CALLBACK FUNCTION Main_CB()
                  
                  FUNCTION PBMAIN()
                  
                  LOCAL hDlg  AS DWORD
                  LOCAL Txt AS STRING
                  
                  DIALOG NEW 0, "Exploring Ogl - Pinning", , , 201, 131, _
                                          %WS_POPUP OR %WS_BORDER _
                                          OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                          %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                          %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                          %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                  
                  CONTROL ADD GRAPHIC, hDlg, %GFX_WIN, "", 5, 5, 190, 80, _
                                                           %SS_SUNKEN OR %SS_NOTIFY OR %WS_CHILD OR _
                                                          %WS_VISIBLE
                  
                  CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
                    OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                    %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                    %WS_EX_LTRREADING
                  
                  CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
                    %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                    OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                    %WS_EX_LTRREADING
                  
                  DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
                  
                  MENU NEW BAR TO MnuHndl
                  MENU NEW POPUP TO ChildHndl
                  MENU ADD POPUP, MnuHndl, "OGL Image Parameters", ChildHndl, %MF_ENABLED
                  
                    MENU ADD STRING, ChildHndl, "Change Winding", %MNU_WINDING, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                  
                    MENU ADD STRING, ChildHndl, "Remove Hidden Surfaces", %MNU_CULL_SURF, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl, "Depth Test", %MNU_DEPTH_TEST, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl, "Lines On Back Side Only", %MNU_BACKSIDE, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl, "Lines On Front Side Only", %MNU_FRONTSIDE, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl, "Lines On Both Sides", %MNU_BOTH, %MF_ENABLED OR %MF_CHECKED, _
                                                 CALL ObjMnu_CB
                    MENU ADD STRING, ChildHndl, "Add Z Factor", %MNU_ADDZ, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                    MENU NEW POPUP TO ChildHndl_2
                    MENU ADD POPUP, ChildHndl, "Rotate", ChildHndl_2, %MF_ENABLED
                      MENU ADD STRING, ChildHndl_2, "Around X Axsis", %MNU_ROTATEX, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl_2, "Around Y Axsis", %MNU_ROTATEY, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl_2, "Around XY Axsis", %MNU_ROTATEXY, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl_2, "Around XZ Axsis", %MNU_ROTATEXZ, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl_2, "Around YZ Axsis", %MNU_ROTATEYZ, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl_2, "Around Z Axsis", %MNU_ROTATEZ, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl_2, "Around All", %MNU_ROTATEALL, %MF_ENABLED, _
                                                 CALL ObjMnu_CB
                  
                  MENU ATTACH MnuHndl, hDlg
                  
                  DIALOG SHOW MODAL hDlg, CALL Main_CB
                  
                  END FUNCTION
                  
                  '------------------------------------------------------------
                  '------------------------------------------------------------
                  
                  CALLBACK FUNCTION Main_CB()
                  
                  LOCAL lParam AS LONG
                  LOCAL wParam AS LONG
                  
                  SELECT CASE AS LONG CBMSG
                  
                    wParam = CBWPARAM
                    CASE %WM_INITDIALOG
                      tFlags.Both = 1
                    CASE %WM_COMMAND
                      wParam = CBCTLMSG
                      SELECT CASE AS LONG wParam
                        CASE %BN_CLICKED, %STN_CLICKED, 1
                          SELECT CASE AS LONG CBCTL
                            CASE %GFX_WIN
                  
                            CASE %BTN_END
                              tFlags.EndProg = 1
                              CALL RunOgl(CBHNDL)
                              DIALOG END CBHNDL
                              FUNCTION = 1
                              EXIT FUNCTION
                  
                            CASE %BTN_OGL
                              CONTROL DISABLE CBHNDL, %BTN_OGL
                              tFlags.OglBtnDead = 1
                              tFlags.RunGlDemo = 1
                              CALL RunOgl(CBHNDL)
                              FUNCTION = 1
                              EXIT FUNCTION
                  
                          END SELECT
                      END SELECT
                  
                    CASE %WM_DESTROY
                      IF tFlags.EndProg THEN EXIT SELECT
                      tFlags.EndProg = 1
                      CALL RunOgl(CBHNDL)
                  
                    CASE %OGL_ERROR
                      SELECT CASE wParam
                        CASE 1
                          MSGBOX "Could not find matching pixel format"
                        CASE 2
                          MSGBOX "Could not set selected pixel format"
                        CASE 3
                          MSGBOX "Could not create rendering context"
                        CASE 4
                          MSGBOX "Could not make rendering context current.  Defined window may not" _
                                 + " support it"
                      END SELECT
                      DIALOG END CBHNDL
                  END SELECT
                  
                  END FUNCTION
                  
                  '------------------------------------------------------------
                  '------------------------------------------------------------
                  
                  SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                  
                  '==============================================================
                  ' This is the 1st step in setting up windows for OpenGl support
                  ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
                  ' graphics
                  '==============================================================
                  
                  pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
                  pfd.nversion = 1
                  pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
                  pfd.dwlayermask = %PFD_MAIN_PLANE
                  pfd.ipixeltype = %PFD_TYPE_RGBA
                  pfd.ccolorbits = 24
                  pfd.cdepthbits = 24
                  pfd.caccumbits = 0
                  pfd.cstencilbits = 0
                  
                  END SUB
                  
                  '---------------------------------------------------------------
                  '---------------------------------------------------------------
                  
                  SUB RunOgl(BYVAL Hndl AS DWORD)
                  
                  STATIC Wide  AS LONG
                  STATIC High  AS LONG
                  
                  STATIC GfxDC     AS DWORD
                  STATIC OglRc     AS DWORD
                  STATIC GfxHndl   AS DWORD
                  
                  LOCAL Img() AS BYTE
                  
                  LOCAL X     AS DOUBLE
                  LOCAL Y     AS DOUBLE
                  LOCAL Z     AS DOUBLE
                  
                  LOCAL Azi AS LONG
                  LOCAL Lazi AS LONG
                  
                  LOCAL HalfWide AS LONG
                  LOCAL HalfHigh AS LONG
                  
                  LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
                  
                  IF ISFALSE(GfxDc) THEN
                    IF tFlags.EndProg THEN EXIT SUB
                  
                    CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                    CALL OglPixFormat(tPixFmt)
                  
                    OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
                  
                    IF OglRc = 0 THEN EXIT SUB
                  
                    CALL SetOglWindow(Wide, High, 100)
                  
                  END IF
                  
                  IF tFlags.EndProg THEN
                    CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                    EXIT SUB
                  END IF
                  
                  IF tFlags.RunGlDemo THEN
                    HalfWide = Wide \ 2
                    HalfHigh = High \ 2
                    CALL glRunDemo(Azi, GfxDc)
                    SLEEP 50
                    Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, CODEPTR(Mouse_SubCB))
                    CONTROL SET USER Hndl, %GFX_WIN, 1, Proc
                    DO
                      DIALOG DOEVENTS
                  
                      IF tFlags.EndProg THEN
                        CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                        EXIT DO
                      END IF
                      IF tMouse.LbDown = 0 THEN ITERATE DO
                  
                      DO
                        DIALOG DOEVENTS
                        CALL Mouse(GfxHndl, 0)
                        Azi = Az(HalfWide, HalfHigh, tMouse.Mx, tMouse.My)
                        CALL glRunDemo(Azi, GfxDc)
                      LOOP UNTIL tMouse.LbDown = 0 OR tFlags.EndProg = 1
                    LOOP
                  END IF
                  
                  SetWindowLong(GfxHndl, %GWL_WNDPROC, Proc)
                  CONTROL SET USER Hndl, %GFX_WIN, 1, 0
                  
                  END SUB
                  
                  '----------------------------------------------------------------
                  '----------------------------------------------------------------
                  
                  FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                      tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                  
                  '================================================================
                  '  This is the second step for OpenGL support
                  '  ChoosePixelFormat selects a pixel format that matches that
                  '  described in the PIXELFORMATDESCRIPTOR structure.
                  '
                  '  Each step in the setup is quried because not all windows support
                  '  OpenGL rendering
                  '================================================================
                  
                  LOCAL PixFormat AS DWORD
                  LOCAL OglRc     AS DWORD
                  
                  LOCAL T AS LONG
                  
                  PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
                  
                  IF ISFALSE (PixFormat) THEN
                    DIALOG POST Hndl, %OGL_ERROR, 1, 0
                    EXIT FUNCTION
                  END IF
                  
                  t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
                  
                  IF ISFALSE(t) THEN
                    DIALOG POST Hndl, %OGL_ERROR, 2, 0
                    EXIT FUNCTION
                  END IF
                  
                  OglRc = wglCreateContext(GfxDc)
                  
                  IF ISFALSE(OglRc) THEN
                    DIALOG POST Hndl, %OGL_ERROR, 3, 0
                    EXIT FUNCTION
                  END IF
                  
                  t = wglMakeCurrent(GfxDc, OglRc)
                  
                  IF ISFALSE(t) THEN
                    DIALOG POST Hndl, %OGL_ERROR, 4, 0
                    EXIT FUNCTION
                  END IF
                  
                  SetOglPipe = OglRc
                  END FUNCTION
                  
                  '----------------------------------------------------------------
                  '----------------------------------------------------------------
                  
                  SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                   BYVAL OrthoRange AS LONG)
                  
                  LOCAL ClearClr AS DWORD
                  
                  LOCAL Aspect AS SINGLE
                  LOCAL Xmin   AS SINGLE
                  LOCAL Ymin   AS SINGLE
                  LOCAL Xmax   AS SINGLE
                  LOCAL Ymax   AS SINGLE
                  LOCAL Zmin   AS SINGLE
                  LOCAL Zmax   AS SINGLE
                  
                  '=================================================================
                  ' This defines the graphics environment.
                  ' Getting this correct is crucial to using OpenGL.
                  '
                  ' In previous examples the orthographic projection was set to the
                  ' window coordinates.  This now changes the projection coordinates
                  ' to something other than the window coordinates.
                  '=================================================================
                  
                  ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                             %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                  
                  IF Wide <= High THEN
                    Aspect! = High / Wide
                  ELSE
                    Aspect! = Wide / High
                  END IF
                  
                  IF Wide <= High THEN
                    Xmin! = -OrthoRange / 2
                    Xmax! = OrthoRange  / 2
                    Ymin! = (-OrthoRange / 2) * Aspect!
                    Ymax! = (OrthoRange / 2) * Aspect!
                  ELSE
                    Xmin! = (-OrthoRange / 2) * Aspect!
                    Xmax! = (OrthoRange / 2) * Aspect!
                    Ymin! = (-OrthoRange / 2)
                    Ymax! = (OrthoRange  / 2)
                  END IF
                  
                  Zmin! = -OrthoRange / 2
                  Zmax! = OrthoRange
                  
                  glViewport(0, 0, Wide, High)
                  glMatrixMode(%GL_PROJECTION)
                  glLoadIdentity
                  glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
                  glMatrixMode(%GL_MODELVIEW)
                  glLoadIdentity
                  glClear(ClearClr)
                  
                  END SUB
                  
                  
                  '----------------------------------------------------------------
                  '----------------------------------------------------------------
                  
                  SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
                  
                  wglMakeCurrent(0, 0)
                  wglDeleteContext(OglRc)
                  ReleaseDc(GfxHndl,GfxDc)
                  
                  END SUB
                  
                  '----------------------------------------------------------------
                  '----------------------------------------------------------------
                  
                  SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                      GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                  
                  CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
                  CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
                  DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
                  
                  GfxDc = GetDc(GfxHndl)
                  
                  END SUB
                  
                  '-----------------------------------------------------------------
                  '-----------------------------------------------------------------
                  
                  SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                  
                  LOCAL tPoint AS POINT
                  
                  GetCursorPos(tPoint)
                  ScreenToClient(GfxHndl, tPoint)
                  
                  tMouse.Mx = tPoint.X
                  tMouse.My = tPoint.Y
                  
                  END SUB
                  
                  '-------------------------------------------------------------------
                  '-------------------------------------------------------------------
                  
                  SUB glRunDemo(BYVAL Azi AS LONG , BYVAL GfxDc AS DWORD)
                  
                  '===================================================================
                  ' Each of the polygons has a local origin as defined by TranslateF()
                  ' or a designated offset from the orthographic projection origin.
                  ' When they are rotated they each rotate around their local origin.
                  ' Notice that the middle polygon rotates around a point that is not
                  ' the center when "rotate around z" is enabled.
                  '===================================================================
                  
                  LOCAL ClearClr AS DWORD
                  
                  LOCAL AngStep   AS LONG
                  LOCAL ValidZ    AS LONG
                  LOCAL InvalidZ  AS LONG
                  
                  LOCAL Pi    AS SINGLE
                  LOCAL Rad   AS SINGLE
                  LOCAL Z     AS SINGLE
                  
                  ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                             %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                  
                  Pi! = 4 * ATN(1)
                  Rad! = Pi! / 180
                  AngStep = 8
                  AngStep = 360 \ AngStep
                  
                  IF tFlags.Winding THEN
                    glFrontFace(%GL_CW)
                  END IF
                  
                  IF tFlags.Surf THEN
                    glEnable(%GL_CULL_FACE)
                  END IF
                  
                  IF tFlags.Test THEN
                    glEnable(%GL_DEPTH_TEST)
                  END IF
                  
                  IF tFlags.Back = 1 THEN
                    glPolygonMode(%GL_BACK, %GL_LINE)
                  END IF
                  
                  IF tFlags.Front = 1 THEN
                    glPolygonMode(%GL_FRONT, %GL_LINE)
                  END IF
                  
                  IF tFlags.Both = 1 THEN
                    glPolygonMode(%GL_FRONT_AND_BACK, %GL_LINE)
                  END IF
                  
                  IF tFlags.AddZ THEN
                    ValidZ = -25
                    InvalidZ = -35
                  END IF
                  
                  '===========================================================
                  ' This is a valid polygon.  It can be normalize and is convex.
                  ' Ogl has no problem rendering it correctly no matter what is
                  ' done to it
                  '===========================================================
                  
                  glPushMatrix
                  glTranslateF(75, 0, 0)
                  glColor3Ub(128, 255, 200)
                  
                  '=========================================================
                  ' Objects are pinned very close to their origin to produce
                  ' a circular rotation
                  '=========================================================
                  IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
                  IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
                  IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
                  IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
                  '==========================================================
                  ' Objects are pinned away from their origin producing an
                  ' oblique rotation and a somewhat different look when the Z
                  ' factor is added.
                  '==========================================================
                  IF tFlags.RotXy THEN glRotateF(Azi, 65, 65, 0)
                  IF tFlags.RotXz THEN glRotateF(Azi, -50, 0, -25)
                  IF tFlags.RotYz THEN glRotateF(Azi, 0, 50, 25)
                  
                  glBegin(%GL_POLYGON)
                  FOR I = 0 TO 360 - AngStep STEP AngStep
                    X = 30 * SIN(I * Rad!)
                    Y = 30 * COS(I * Rad!)
                    glVertex3F(X, Y, ValidZ)
                    IF tFlags.AddZ THEN
                      IF I >= 90 THEN
                        ValidZ = ValidZ + 20
                      END IF
                    END IF
                  NEXT I
                  glEnd
                  glPopMatrix
                  
                  '======================================================
                  ' This is an invalid polygon because it resides in two
                  ' planes, i.e., the verticies cross; therefore it cannot
                  ' be normalized and Ogl has problems rendering it correctly.
                  '======================================================
                  
                  glPushMatrix
                  glTranslateF(25, 0, 0)
                  glColor3Ub(255, 128, 200)
                  
                  IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
                  IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
                  IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
                  IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
                  
                  IF tFlags.RotXy THEN glRotateF(Azi, -35, 35, 0)
                  IF tFlags.RotXz THEN glRotateF(Azi, 35, 0, -50)
                  IF tFlags.RotYz THEN glRotateF(Azi, 0, -45, 50)
                  
                  glBegin(%GL_QUADS)
                  
                  IF tFlags.AddZ THEN
                    glVertex3F(-35, 35, InvalidZ)
                    glVertex3F(05, -35, 0)
                    glVertex3F(-35, -35, 0)
                    glVertex3F(05, 35, InvlaidZ + 50)
                  ELSE
                    glVertex3F(-35, 35, 0)
                    glVertex3F(05, -35, 0)
                    glVertex3F(-35, -35, 0)
                    glVertex3F(05, 35, 0)
                  END IF
                  
                  glEnd
                  glPopMatrix
                  
                  '========================================================
                  ' This is an invalid polygon.  Although no verticies cross,
                  ' it is not convex; therefore Ogl has problems rendering it
                  ' correctly.
                  '========================================================
                  
                  glPushMatrix
                  glTranslateF(-65, 0, 0)
                  glColor3Ub(126, 0, 200)
                  
                  IF tFlags.RotX THEN glRotateF(Azi, .001, 0, 0)
                  IF tFlags.RotY THEN glRotateF(Azi, 0, .001, 0)
                  IF tFlags.RotZ THEN glRotateF(Azi, 0, 0, .001)
                  IF tFlags.RotA THEN glRotateF(Azi, .001, .001, .001)
                  
                  IF tFlags.RotXy THEN glRotateF(Azi, 35, -35, 0)
                  IF tFlags.RotXz THEN glRotateF(Azi, -60, 0, 75)
                  IF tFlags.RotYz THEN glRotateF(Azi, 0, 75, -50)
                  
                  glBegin(%GL_POLYGON)
                  
                  IF tFlags.AddZ THEN
                    glVertex3F(-35, 35, InvalidZ)
                    glVertex3F(-15, 15, 0)
                    glVertex3F(05, 35, InvalidZ - 10)
                    glVertex3F(10, 0, InvalidZ + 50)
                    glVertex3F(35, -35, 0)
                    glVerTex3f(-35, -35, InvalidZ - 30)
                  ELSE
                    glVertex3F(-35, 35, 0)
                    glVertex3F(-15, 15, 0)
                    glVertex3F(05, 35, 0)
                    glVertex3F(10, 0, 0)
                    glVertex3F(35, -35, 0)
                    glVerTex3f(-35, -35, 0)
                  END IF
                  
                  glEnd
                  glPopMatrix
                  
                  SwapBuffers(GfxDc)
                  glClear(ClearClr)
                  
                  glFlush
                  
                  glFrontFace(%GL_CCW)
                  glDisable(%GL_CULL_FACE)
                  glDisable(%GL_DEPTH_TEST)
                  glPolygonMode(%GL_FRONT_AND_BACK, %GL_FILL)
                  
                  glFinish
                  
                  END SUB
                  
                  '------------------------------------------------------------------
                  '------------------------------------------------------------------
                  
                  CALLBACK FUNCTION Mouse_SubCB
                  
                  LOCAL Hndl      AS DWORD
                  LOCAL OrigProc  AS DWORD
                  LOCAL Gfx_Hndl  AS DWORD
                  
                  Hndl = CBHNDL
                  Gfx_Hndl = GetDlgCtrlId(Hndl)
                  OrigProc = GetParent(Hndl)
                  CONTROL GET USER OrigProc, Gfx_Hndl, 1 TO OrigProc
                  IF OrigProc = 0 THEN EXIT FUNCTION
                  
                  SELECT CASE CBMSG
                    CASE IS %WM_LBUTTONDOWN
                      tMouse.LbDown = 1
                      FUNCTION = 1
                      EXIT FUNCTION
                  
                    CASE IS %WM_LBUTTONUP
                      tMouse.LbClk = 1
                      tMouse.LbDown = 0
                      FUNCTION = 1
                      EXIT FUNCTION
                  
                    CASE IS %WM_RBUTTONDOWN
                      tMouse.RbDown = 1
                      tMouse.LbDown = 0
                      FUNCTION = 1
                      EXIT FUNCTION
                  
                    CASE IS %WM_RBUTTONUP
                      tMouse.RbClk = 1
                      tMouse.RbDown = 0
                      FUNCTION = 1
                      EXIT FUNCTION
                  
                  END SELECT
                  
                  FUNCTION = CallWindowProc(OrigProc, Hndl, CBMSG, CBWPARAM, CBLPARAM)
                  END FUNCTION
                  
                  '--------------------------------------------------
                  '--------------------------------------------------
                  FUNCTION Az(BYVAL X1 AS SINGLE, BYVAL Y1 AS SINGLE, _
                              BYVAL X2 AS SINGLE, BYVAL Y2 AS SINGLE) AS SINGLE
                  
                  LOCAL Deg AS SINGLE
                  LOCAL X   AS SINGLE
                  LOCAL Y   AS SINGLE
                  
                  Deg! = 180 / (4 * ATN(1))
                  X! = X2 - X1
                  Y! = Y2 - Y1
                  
                  SELECT CASE Y!
                    CASE IS < 0.0!
                      Az! = -ATN(X! / Y!) * Deg!
                      IF X! < 0.0! THEN Az! = 360.0! - ATN(X! / Y!) * Deg!
                  
                    CASE IS > 0.0!
                      Az! = 180.0! - ATN(X! / Y!) * Deg!
                  
                    CASE IS 0.0!
                      IF X! > 0.0! THEN Az! = 90.0!
                      IF X! < 0.0! THEN Az! = 270.0!
                  END SELECT
                  
                  END FUNCTION
                  
                  '---------------------------------------------------------
                  '---------------------------------------------------------
                  
                  SUB RegWindow(Nam AS ASCIIZ, BYVAL Styl AS DWORD, BYVAL Code_Ptr AS DWORD, _
                                           BYVAL Inst AS DWORD, BYVAL BkBrush AS DWORD, RegOk AS BYTE)
                  
                  LOCAL tWindow AS WNDCLASSEX
                  
                  tWindow.cbSize        = SIZEOF(tWindow)
                  tWindow.style         = Styl
                  tWindow.lpfnWndProc   = Code_Ptr
                  tWindow.cbClsExtra    = 0
                  tWindow.cbWndExtra    = 32
                  tWindow.hInstance     = Inst
                  tWindow.hIcon         = %NULL
                  tWindow.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                  
                  IF BkBrush = 0 THEN
                    tWindow.hbrBackground = 0
                  ELSE
                    tWindow.hbrBackground = GetStockObject(BkBrush)
                  END IF
                  
                  tWindow.lpszMenuName  = %NULL
                  tWindow.lpszClassName = VARPTR(Nam$)
                  tWindow.hIconSm       = %NULL
                  
                  Styl = RegisterClassEx(tWindow)
                  
                  IF Styl THEN RegOk = 1
                  
                  END SUB
                  
                  CALLBACK FUNCTION ObjMnu_CB()
                  
                  
                  IF CBMSG = %WM_COMMAND THEN
                    IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                  
                      SELECT CASE CBCTL
                        CASE %MNU_WINDING
                          IF tFlags.Winding = 1 THEN
                            tFlags.Winding = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_UNCHECKED OR %MF_ENABLED
                          ELSE
                            tFlags.Winding = 1
                            MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_CHECKED OR %MF_ENABLED
                          END IF
                  
                        CASE %MNU_CULL_SURF
                          IF tFlags.Surf = 1 THEN
                            tFlags.Surf= 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_UNCHECKED OR %MF_ENABLED
                          ELSE
                            tFlags.Surf = 1
                            MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_CHECKED OR %MF_ENABLED
                          END IF
                  
                        CASE %MNU_DEPTH_TEST
                          IF tFlags.Test = 1 THEN
                            tFlags.Test = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_UNCHECKED OR %MF_ENABLED
                          ELSE
                            tFlags.Test = 1
                            MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_CHECKED OR %MF_ENABLED
                          END IF
                  
                        CASE %MNU_BACKSIDE
                          IF tFlags.Back THEN
                            tFlags.Back = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.Back = 1
                          tFlags.Front = 0
                          tFlags.Both = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_FRONTSIDE
                          IF tFlags.Front THEN
                            tFlags.Front = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.Back = 0
                          tFlags.Front = 1
                          tFlags.Both = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_BOTH
                          IF tFlags.Both THEN
                            tFlags.Both = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.Back = 0
                          tFlags.Front = 0
                          tFlags.Both = 1
                          MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_CHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ADDZ
                          IF tFlags.AddZ THEN
                            MENU SET STATE MnuHndl, BYCMD %MNU_ADDZ, %MF_UNCHECKED OR %MF_ENABLED
                            tFlags.AddZ = 0
                            EXIT SELECT
                          END IF
                          MENU SET STATE MnuHndl, BYCMD %MNU_ADDZ, %MF_CHECKED OR %MF_ENABLED
                          tFlags.AddZ = 1
                  
                        CASE %MNU_ROTATEX
                          IF tFlags.RotX THEN
                            tFlags.RotX = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotX = 1
                          tFlags.RotY = 0
                          tFlags.RotZ = 0
                          tFlags.RotA = 0
                          tFlags.RotXy = 0
                          tFlags.RotXz = 0
                          tFlags.RotYz = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ROTATEY
                          IF tFlags.RotY THEN
                            tFlags.RotY = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotY = 1
                          tFlags.RotX = 0
                          tFlags.RotZ = 0
                          tFlags.RotA = 0
                          tFlags.RotXy = 0
                          tFlags.RotXz = 0
                          tFlags.RotYz = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ROTATEZ
                          IF tFlags.RotZ THEN
                            tFlags.RotZ = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotZ = 1
                          tFlags.RotX = 0
                          tFlags.RotY = 0
                          tFlags.RotA = 0
                          tFlags.RotXy = 0
                          tFlags.RotXz = 0
                          tFlags.RotYz = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ROTATEALL
                          IF tFlags.RotA THEN
                            tFlags.RotA = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotA = 1
                          tFlags.RotX = 0
                          tFlags.RotY = 0
                          tFlags.RotZ = 0
                          tFlags.RotXy = 0
                          tFlags.RotXz = 0
                          tFlags.RotYz = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ROTATEXY
                          IF tFlags.RotXY THEN
                            tFlags.RotXY = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotX = 0
                          tFlags.RotY = 0
                          tFlags.RotZ = 0
                          tFlags.RotA = 0
                          tFlags.RotXY = 1
                          tFlags.RotXz = 0
                          tFlags.RotYz = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ROTATEXZ
                          IF tFlags.RotXZ THEN
                            tFlags.RotXZ = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotXZ = 1
                          tFlags.RotX = 0
                          tFlags.RotY = 0
                          tFlags.RotXY = 0
                          tFlags.RotYz = 0
                          tFlags.RotZ = 0
                          tFlags.RotA = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                  
                        CASE %MNU_ROTATEYZ
                          IF tFlags.RotYZ THEN
                            tFlags.RotYZ = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_UNCHECKED OR %MF_ENABLED
                            EXIT SELECT
                          END IF
                          tFlags.RotYZ = 1
                          tFlags.RotXy = 0
                          tFlags.RotXz = 0
                          tFlags.RotX = 0
                          tFlags.RotY = 0
                          tFlags.RotZ = 0
                          tFlags.RotA = 0
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEYZ, %MF_CHECKED OR %MF_ENABLED
                          MENU SET STATE Mnuhndl, BYCMD %MNU_ROTATEXY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEXZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                          MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEALL, %MF_UNCHECKED OR %MF_ENABLED
                  
                      END SELECT
                    END IF
                  END IF
                  END FUNCTION
                  
                  '---------------------------------------------------------------
                  '---------------------------------------------------------------
                  Walt Decker

                  Comment


                  • #10
                    Rotation, Translation, and Color

                    Although objects rotate around their local origins, movement around
                    the rendering surface is accomplished by either rotating the objects
                    first then moving (translating) the objects to a new location or by
                    moving the objects first then rotating them. They can even be moved
                    out of view while still on the rendering surface.

                    Color is defined by vertex and not by object. When only one color
                    is specified for an object, that color is used for all verticies.
                    However; when more than one color is specifed, the colors are
                    "smoothly" blended to produce some interesting effects. This blending
                    can be cancelled by using glShadeModel() with the argument %GL_FLAT to
                    produce non-blended colors.

                    The following example demonstrates these effects.

                    Code:
                    '=======================================================================
                    '               ROTATION, TRANSLATION, AND COLOR
                    '-----------------------------------------------------------------------
                    '   Although objects rotate around their local origins, movement around
                    ' the rendering surface is accomplished by either rotating the objects
                    ' first then moving (translating) the objects to a new location or by
                    ' moving the objects first then rotating them.  They can even be moved
                    ' out of view while still on the rendering surface.
                    '
                    '   Color is defined by vertex and not by object.  When only one color
                    ' is specified for an object, that color is used for all verticies.
                    ' However; when more than one color is specifed, the colors are
                    ' "smoothly" blended to produce some interesting effects.  This blending
                    ' can be cancelled by using glShadeModel() with the argument %GL_FLAT to
                    ' produce non-blended colors.
                    '-----------------------------------------------------------------------
                    '
                    '=======================================================================
                    '                            OPENGL FUNCTIONS USED
                    '=======================================================================
                    ' glViewport()
                    ' glMatrixMode()
                    ' glLoadIdentity
                    ' glOrtho()
                    ' glclear()
                    ' glPushMatrix
                    ' glTranslatef()
                    ' glColor3Ub()
                    ' glBegin()
                    ' glEnd
                    ' glVertex3F()
                    ' glPopMatrix
                    ' glEnable()
                    ' glDisable()
                    ' glFlush
                    ' glFinish
                    ' glShadeModel()
                    '=========================================================================
                    '                            WINDOWS FUNCTIONS USED
                    '=========================================================================
                    ' GetDc
                    ' ReleaseDc
                    ' ChoosePixelFormat
                    ' SetPixelFormat
                    ' wglCreateContext
                    ' wglMakeCurrent
                    ' wglDeleteContext
                    ' SetWindowLong
                    '=========================================================================
                    
                    #COMPILE EXE
                    
                    DEFLNG A - Z
                    
                    #INCLUDE "WIN32API.INC"
                    #INCLUDE "gl.inc"
                    #INCLUDE "glu.inc"
                    
                    TYPE MenuFlag_STRUCT
                      Winding   AS BIT * 1 IN BYTE
                      Surf      AS BIT * 1
                      Test      AS BIT * 1
                      Back      AS BIT * 1
                      Front     AS BIT * 1
                      Both      AS BIT * 1
                      Trans     AS BIT * 1
                      FlatClr   AS BIT * 1
                    END TYPE
                    
                    TYPE OglFlag_STRUCT
                      EndProg     AS BIT * 1 IN BYTE
                      MouseClk    AS BIT * 1
                      OglBtnDead  AS BIT * 1
                      RunGlDemo   AS BIT * 1
                      MenuFlag_STRUCT
                    END TYPE
                    
                    TYPE Button_STRUCT
                      LbDown AS BIT * 1 IN BYTE
                      LbClk  AS BIT * 1
                      RbDown AS BIT * 1
                      RbClk  AS BIT * 1
                    END TYPE
                    
                    TYPE Single2_STRUCT
                      Mx  AS SINGLE
                      My  AS SINGLE
                    END TYPE
                    
                    TYPE Mouse_STRUCT
                      Single2_STRUCT
                      Button_STRUCT
                    END TYPE
                    
                    
                    MACRO GL_FAC = 0.375!     '   Fudge factor used with glTranslateF to plot coordinates
                                              '   correctly while in 2dimensional mode
                    
                    %GFX_WIN     =    5
                    %BTN_END     =    6
                    %BTN_OGL     =    7
                    
                    %MNU_WINDING    = 50
                    %MNU_CULL_SURF  = 51
                    %MNU_DEPTH_TEST = 52
                    %MNU_BACKSIDE   = 53
                    %MNU_FRONTSIDE  = 54
                    %MNU_BOTH       = 55
                    %MNU_TRANS      = 56
                    %MNU_FLATCLR    = 57
                    
                    %OGL_ERROR   = %WM_USER + 500
                    
                    GLOBAL tFlags AS OglFlag_STRUCT
                    GLOBAL tMouse AS Mouse_STRUCT
                    GLOBAL MnuHndl AS DWORD
                    
                    DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                    DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
                    DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                                GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                    
                    DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                            BYVAL GfxHndl AS DWORD)
                    
                    DECLARE SUB OglRenderImage(BYVAL X AS DOUBLE, BYVAL Y AS DOUBLE, BYVAL GfxDc AS DWORD)
                    
                    DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                    
                    
                    DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                                tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                    
                    
                    DECLARE FUNCTION PBMAIN() AS LONG
                    DECLARE CALLBACK FUNCTION Main_CB()
                    
                    FUNCTION PBMAIN()
                    
                    LOCAL hDlg  AS DWORD
                    
                    DIALOG NEW 0, "Exploring Ogl - Translation, Rotation & Color", , , 201, 131, _
                                            %WS_POPUP OR %WS_BORDER _
                                            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                            %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                            %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                            %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                    
                    CONTROL ADD GRAPHIC, hDlg, %GFX_WIN, "", 5, 5, 190, 80, _
                                                             %SS_SUNKEN OR %SS_NOTIFY OR %WS_CHILD OR _
                                                            %WS_VISIBLE
                    
                    CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
                      OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                      %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                      %WS_EX_LTRREADING
                    
                    CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
                      %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                      OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                      %WS_EX_LTRREADING
                    
                    DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
                    
                    MENU NEW BAR TO MnuHndl
                    MENU NEW POPUP TO ChildHndl
                    MENU ADD POPUP, MnuHndl, "OGL Image Parameters", ChildHndl, %MF_ENABLED
                    
                      MENU ADD STRING, ChildHndl, "Change Winding", %MNU_WINDING, %MF_ENABLED, _
                                                   CALL ObjMnu_CB
                    
                      MENU ADD STRING, ChildHndl, "Remove Hidden Surfaces", %MNU_CULL_SURF, %MF_ENABLED, _
                                                   CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl, "Depth Test", %MNU_DEPTH_TEST, %MF_ENABLED OR %MF_CHECKED, _
                                                   CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl, "Lines On Back Side Only", %MNU_BACKSIDE, %MF_ENABLED, _
                                                   CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl, "Lines On Front Side Only", %MNU_FRONTSIDE, %MF_ENABLED, _
                                                   CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl, "Lines On Both Sides", %MNU_BOTH, %MF_ENABLED, _
                                                   CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl, "Translate Objects", %MNU_TRANS, %MF_ENABLED, _
                                                   CALL ObjMnu_CB
                      MENU ADD STRING, ChildHndl, "Solid Color", %MNU_FLATCLR, %MF_ENABLED OR %MF_CHECKED, _
                                                   CALL ObjMnu_CB
                    
                    MENU ATTACH MnuHndl, hDlg
                    
                    DIALOG SHOW MODAL hDlg, CALL Main_CB
                    
                    END FUNCTION
                    
                    '------------------------------------------------------------
                    '------------------------------------------------------------
                    
                    CALLBACK FUNCTION Main_CB()
                    
                    LOCAL lParam AS LONG
                    LOCAL wParam AS LONG
                    
                    SELECT CASE AS LONG CBMSG
                    
                      wParam = CBWPARAM
                      CASE %WM_INITDIALOG
                        tFlags.FlatClr = 1
                        tFlags.Test = 1
                      CASE %WM_COMMAND
                        wParam = CBCTLMSG
                        SELECT CASE AS LONG wParam
                          CASE %BN_CLICKED, %STN_CLICKED, 1
                            SELECT CASE AS LONG CBCTL
                              CASE %GFX_WIN
                    
                              CASE %BTN_END
                                tFlags.EndProg = 1
                                CALL RunOgl(CBHNDL)
                                DIALOG END CBHNDL
                                FUNCTION = 1
                                EXIT FUNCTION
                    
                              CASE %BTN_OGL
                                CONTROL DISABLE CBHNDL, %BTN_OGL
                                tFlags.OglBtnDead = 1
                                tFlags.RunGlDemo = 1
                                CALL RunOgl(CBHNDL)
                                FUNCTION = 1
                                EXIT FUNCTION
                    
                            END SELECT
                        END SELECT
                    
                      CASE %WM_DESTROY
                        IF tFlags.EndProg THEN EXIT SELECT
                        tFlags.EndProg = 1
                        CALL RunOgl(CBHNDL)
                    
                      CASE %OGL_ERROR
                        SELECT CASE wParam
                          CASE 1
                            MSGBOX "Could not find matching pixel format"
                          CASE 2
                            MSGBOX "Could not set selected pixel format"
                          CASE 3
                            MSGBOX "Could not create rendering context"
                          CASE 4
                            MSGBOX "Could not make rendering context current.  Defined window may not" _
                                   + " support it"
                        END SELECT
                        DIALOG END CBHNDL
                    END SELECT
                    
                    END FUNCTION
                    
                    '------------------------------------------------------------
                    '------------------------------------------------------------
                    
                    SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                    
                    '==============================================================
                    ' This is the 1st step in setting up windows for OpenGl support
                    ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
                    ' graphics
                    '==============================================================
                    
                    pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
                    pfd.nversion = 1
                    pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
                    pfd.dwlayermask = %PFD_MAIN_PLANE
                    pfd.ipixeltype = %PFD_TYPE_RGBA
                    pfd.ccolorbits = 24
                    pfd.cdepthbits = 24
                    pfd.caccumbits = 0
                    pfd.cstencilbits = 0
                    
                    END SUB
                    
                    '---------------------------------------------------------------
                    '---------------------------------------------------------------
                    
                    SUB RunOgl(BYVAL Hndl AS DWORD)
                    
                    STATIC Wide  AS LONG
                    STATIC High  AS LONG
                    
                    STATIC GfxDC     AS DWORD
                    STATIC OglRc     AS DWORD
                    STATIC GfxHndl   AS DWORD
                    
                    LOCAL Img() AS BYTE
                    
                    LOCAL X     AS DOUBLE
                    LOCAL Y     AS DOUBLE
                    LOCAL Z     AS DOUBLE
                    
                    LOCAL Azi AS LONG
                    LOCAL Lazi AS LONG
                    
                    LOCAL HalfWide AS LONG
                    LOCAL HalfHigh AS LONG
                    
                    LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
                    
                    IF ISFALSE(GfxDc) THEN
                      IF tFlags.EndProg THEN EXIT SUB
                    
                      CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                      CALL OglPixFormat(tPixFmt)
                    
                      OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
                    
                      IF OglRc = 0 THEN EXIT SUB
                    
                      CALL SetOglWindow(Wide, High, 100)
                    
                    END IF
                    
                    
                    'IF tFlags.MouseClk THEN
                    '  CALL Mouse(GfxHndl, 0)
                    '  X = tMouse.Mx
                    '                          '==========================================
                    '                          ' Since windows places 0,0 at the upper
                    '  Y = High - tMouse.My    ' left corner of the display and Ogl locates
                    '                          ' 0,0 at the lower left corner the Y coordinate
                    '                          ' must be adjusted.
                    '                          '==========================================
                    '  CALL OglRenderImage(X, Y, GfxDc)
                    '
                    '  tFlags.MouseClk = 0
                    '  EXIT SUB
                    'END IF
                    
                    
                    IF tFlags.RunGlDemo THEN
                      CALL glRunDemo(Azi, GfxDc)
                      SLEEP 50
                      Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, CODEPTR(Mouse_SubCB))
                      CONTROL SET USER Hndl, %GFX_WIN, 1, Proc
                      HalfWide = Wide \ 2
                      HalfHigh = High \ 2
                      DO
                        DIALOG DOEVENTS
                        IF tFlags.EndProg THEN
                          CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                          GfxDc = 0
                          EXIT DO
                        END IF
                        IF tFlags.MouseClk = 0 THEN ITERATE DO
                        DO
                          DIALOG DOEVENTS
                          CALL Mouse(GfxHndl, 0)
                          Azi = Az(HalfWide, HalfHigh, tMouse.Mx, tMouse.My)
                          CALL glRunDemo(Azi, GfxDc)
                          IF tFlags.MouseClk = 0 THEN EXIT DO
                        LOOP
                      LOOP
                    END IF
                    
                    SetWindowLong(GfxHndl, %GWL_WNDPROC, Proc)
                    CONTROL SET USER Hndl, %GFX_WIN, 1, 0
                    
                    END SUB
                    
                    '----------------------------------------------------------------
                    '----------------------------------------------------------------
                    
                    FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                        tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                    
                    '================================================================
                    '  This is the second step for OpenGL support
                    '  ChoosePixelFormat selects a pixel format that matches that
                    '  described in the PIXELFORMATDESCRIPTOR structure.
                    '
                    '  Each step in the setup is quried because not all windows support
                    '  OpenGL rendering
                    '================================================================
                    
                    LOCAL PixFormat AS DWORD
                    LOCAL OglRc     AS DWORD
                    
                    LOCAL T AS LONG
                    
                    PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
                    
                    IF ISFALSE (PixFormat) THEN
                      DIALOG POST Hndl, %OGL_ERROR, 1, 0
                      EXIT FUNCTION
                    END IF
                    
                    t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
                    
                    IF ISFALSE(t) THEN
                      DIALOG POST Hndl, %OGL_ERROR, 2, 0
                      EXIT FUNCTION
                    END IF
                    
                    OglRc = wglCreateContext(GfxDc)
                    
                    IF ISFALSE(OglRc) THEN
                      DIALOG POST Hndl, %OGL_ERROR, 3, 0
                      EXIT FUNCTION
                    END IF
                    
                    t = wglMakeCurrent(GfxDc, OglRc)
                    
                    IF ISFALSE(t) THEN
                      DIALOG POST Hndl, %OGL_ERROR, 4, 0
                      EXIT FUNCTION
                    END IF
                    
                    SetOglPipe = OglRc
                    END FUNCTION
                    
                    '----------------------------------------------------------------
                    '----------------------------------------------------------------
                    
                    SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                     BYVAL OrthoRange AS LONG)
                    
                    LOCAL ClearClr AS DWORD
                    
                    LOCAL Aspect AS SINGLE
                    LOCAL Xmin   AS SINGLE
                    LOCAL Ymin   AS SINGLE
                    LOCAL Xmax   AS SINGLE
                    LOCAL Ymax   AS SINGLE
                    LOCAL Zmin   AS SINGLE
                    LOCAL Zmax   AS SINGLE
                    
                    '=================================================================
                    ' This defines the graphics environment.
                    ' Getting this correct is crucial to using OpenGL.
                    '
                    ' In previous examples the orthographic projection was set to the
                    ' window coordinates.  This now changes the projection coordinates
                    ' to something other than the window coordinates.
                    '=================================================================
                    
                    ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                               %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                    
                    IF Wide <= High THEN
                      Aspect! = High / Wide
                    ELSE
                      Aspect! = Wide / High
                    END IF
                    
                    IF Wide <= High THEN
                      Xmin! = -OrthoRange / 2
                      Xmax! = OrthoRange  / 2
                      Ymin! = (-OrthoRange / 2) * Aspect!
                      Ymax! = (OrthoRange / 2) * Aspect!
                    ELSE
                      Xmin! = (-OrthoRange / 2) * Aspect!
                      Xmax! = (OrthoRange / 2) * Aspect!
                      Ymin! = (-OrthoRange / 2)
                      Ymax! = (OrthoRange  / 2)
                    END IF
                    
                    Zmin! = -OrthoRange / 2
                    Zmax! = OrthoRange
                    
                    glViewport(0, 0, Wide, High)
                    glMatrixMode(%GL_PROJECTION)
                    glLoadIdentity
                    glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
                    glMatrixMode(%GL_MODELVIEW)
                    glLoadIdentity
                    glClear(ClearClr)
                    
                    END SUB
                    
                    
                    '----------------------------------------------------------------
                    '----------------------------------------------------------------
                    
                    SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
                    
                    wglMakeCurrent(0, 0)
                    wglDeleteContext(OglRc)
                    ReleaseDc(GfxHndl,GfxDc)
                    
                    END SUB
                    
                    '----------------------------------------------------------------
                    '----------------------------------------------------------------
                    
                    SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                        GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                    
                    CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
                    CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
                    DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
                    
                    GfxDc = GetDc(GfxHndl)
                    
                    END SUB
                    
                    '-----------------------------------------------------------------
                    '-----------------------------------------------------------------
                    
                    SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                    
                    LOCAL tPoint AS POINT
                    
                    GetCursorPos(tPoint)
                    ScreenToClient(GfxHndl, tPoint)
                    
                    tMouse.Mx = tPoint.X
                    tMouse.My = tPoint.Y
                    
                    END SUB
                    
                    '-------------------------------------------------------------------
                    '-------------------------------------------------------------------
                    
                    SUB glRunDemo(BYVAL Azi AS LONG , BYVAL GfxDc AS DWORD)
                    
                    LOCAL ClearClr AS DWORD
                    
                    LOCAL AngStep AS LONG
                    
                    LOCAL Pi    AS SINGLE
                    LOCAL Rad   AS SINGLE
                    LOCAL Z     AS SINGLE
                    
                    LOCAL Flip AS BYTE
                    
                    STATIC Trans_Flag   AS BYTE
                    STATIC TransLimit   AS BYTE
                    STATIC TransStep    AS SINGLE
                    STATIC Trans_LEFT   AS SINGLE
                    STATIC Trans_RIGHT  AS SINGLE
                    STATIC Trans_Z      AS SINGLE
                    
                    ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                               %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                    
                    Pi! = 4 * ATN(1)
                    Rad! = Pi! / 180
                    AngStep = 8
                    AngStep = 360 \ AngStep
                    
                    IF tFlags.Trans THEN
                      IF Trans_Flag = 0 THEN
                        Trans_RIGHT = 35!
                        Trans_LEFT = -35!
                        Trans_Z = + 60!
                        Trans_Flag = 1
                        TransStep = .5!
                      END IF
                    END IF
                    
                    IF tFlags.Winding THEN
                      glFrontFace(%GL_CW)
                    END IF
                    
                    IF tFlags.Surf THEN
                      glEnable(%GL_CULL_FACE)
                    END IF
                    
                    IF tFlags.Test THEN
                      glEnable(%GL_DEPTH_TEST)
                    END IF
                    
                    IF tFlags.Back = 1 THEN
                      glPolygonMode(%GL_BACK, %GL_LINE)
                    END IF
                    
                    IF tFlags.Front = 1 THEN
                      glPolygonMode(%GL_FRONT, %GL_LINE)
                    END IF
                    
                    IF tFlags.Both = 1 THEN
                      glPolygonMode(%GL_FRONT_AND_BACK, %GL_LINE)
                    END IF
                    
                    IF tFlags.FlatClr THEN
                      glShadeModel(%GL_FLAT)
                    END IF
                    
                    glPushMatrix
                    glTranslateF(Trans_RIGHT, 0, Trans_Z)
                    Z = -50
                    glColor3Ub(128, 255, 200)
                    
                    glrotateF(Azi, 100, -200, -100)
                    glBegin(%GL_POLYGON)
                    FOR I = 0 TO 360 - AngStep STEP AngStep
                      X = 30 * SIN(I * Rad!)
                      Y = 30 * COS(I * Rad!)
                      glVertex3F(X, Y, Z)
                      IF I >= 180 THEN Z = Z + 25
                    NEXT I
                    glEnd
                    glPopMatrix
                    
                    glPushMatrix
                    glTranslateF(0, Trans_LEFT, -Trans_Z)
                    Z = -50
                    glColor3Ub(255, 128, 200)
                    
                    
                    glrotateF(-Azi, 60, 100, -50)
                    glBegin(%GL_POLYGON)
                    FOR I = 0 TO 360 - AngStep STEP AngStep
                      X = 30 * SIN(I * Rad!)
                      Y = 30 * COS(I * Rad!)
                      glVertex3F(X, Y, Z)
                      IF I >= 180 THEN Z = Z + 30
                      IF I >= 90 THEN
                        IF Flip = 0 THEN glColor3Ub(128, 255, 255)
                        IF Flip = 1 THEN glColor3Ub(255, 0, 128)
                        IF Flip = 2 THEN glColor3Ub(128, 128, 128)
                        INCR Flip
                      END IF
                    NEXT I
                    glEnd
                    glPopMatrix
                    SwapBuffers(GfxDc)
                    glClear(ClearClr)
                    
                    glClear(ClearClr)
                    
                    glFlush
                    
                    glFrontFace(%GL_CCW)
                    glDisable(%GL_CULL_FACE)
                    glDisable(%GL_DEPTH_TEST)
                    glPolygonMode(%GL_FRONT_AND_BACK, %GL_FILL)
                    glShadeModel(%GL_SMOOTH)
                    glFinish
                    
                    IF tFlags.Trans THEN
                      IF TransLimit = 0 THEN
                        Trans_RIGHT = Trans_RIGHT - TransStep
                        Trans_LEFT = Trans_LEFT + TransStep
                        Trans_Z = Trans_Z - TransStep
                        IF Trans_RIGHT < -50! THEN TransLimit = 1
                      ELSE
                        Trans_RIGHT = Trans_RIGHT + TransStep
                        Trans_LEFT = Trans_LEFT - TransStep
                        Trans_Z = Trans_Z + TransStep
                        IF Trans_RIGHT > 100! THEN TransLimit = 0
                      END IF
                    END IF
                    
                    
                    END SUB
                    
                    '------------------------------------------------------------------
                    '------------------------------------------------------------------
                    
                    SUB WindowToProjection(X AS DOUBLE, Y AS DOUBLE, Z AS DOUBLE)
                    
                    '============================================================
                    ' Since the orthographic coordinate system does not reflect
                    ' the window coordinate system, the window coordinate system
                    ' is translated to the ortho system by gluUnProject().
                    '
                    ' That OpenGL function uses the window values and the values
                    ' stored in the viewport matrix, the modle matrix and the
                    ' projection matrix to calculate the ortho coordinates.  This
                    ' routine can also be used to calculate the perspective view
                    ' coordinates.
                    '
                    ' Because OpenGL uses the various matricies for it's calculations
                    ' we have to get those matricies before calling gluUnProject().
                    ' That's what the various forms of glGet...() do.  Along with
                    ' our window coordinates we pass those matricies to gluUnProject()
                    ' and it returns the OGL coordinates in the last three parameters:
                    ' WinX, WinY, WinZ.
                    '============================================================
                    
                    LOCAL WinViewport()   AS LONG
                    LOCAL ModleMatrix()   AS DOUBLE
                    LOCAL ProjectMatrix() AS DOUBLE
                    
                    LOCAL WinX AS DOUBLE
                    LOCAL WinY AS DOUBLE
                    LOCAL WinZ AS DOUBLE
                    
                    DIM WinViewPort(0 TO 1, 0 TO 1)    '<--- 4 element array
                    DIM ModleMatrix(0 TO 3, 0 TO 3)    '<--- 16 element array
                    DIM ProjectMatrix(0 TO 3, 0 TO 3)
                    
                    glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
                    glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
                    glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
                    
                    gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
                    
                    X = WinX
                    Y = WinY
                    Z = WinZ
                    
                    END SUB
                    
                    '--------------------------------------------------------
                    '--------------------------------------------------------
                    
                    CALLBACK FUNCTION Mouse_SubCB
                    
                    LOCAL Hndl      AS DWORD
                    LOCAL OrigProc  AS DWORD
                    LOCAL Gfx_Hndl  AS DWORD
                    
                    Hndl = CBHNDL
                    Gfx_Hndl = GetDlgCtrlId(Hndl)
                    OrigProc = GetParent(Hndl)
                    CONTROL GET USER OrigProc, Gfx_Hndl, 1 TO OrigProc
                    IF OrigProc = 0 THEN EXIT FUNCTION
                    
                    SELECT CASE CBMSG
                      CASE IS %WM_LBUTTONDOWN
                        tFlags.MouseClk = 1
                        FUNCTION = 1
                        EXIT FUNCTION
                    
                      CASE IS %WM_LBUTTONUP
                        tFlags.MouseClk = 0
                        FUNCTION = 1
                        EXIT FUNCTION
                    
                      CASE IS %WM_RBUTTONDOWN
                        FUNCTION = 1
                        EXIT FUNCTION
                    
                      CASE IS %WM_RBUTTONUP
                        tFlags.EndProg = 1
                        FUNCTION = 1
                        EXIT FUNCTION
                    
                    '  CASE IS %WM_MOUSEMOVE
                    '    IF (CBWPARAM AND %MK_LBUTTON) = %MK_LBUTTON THEN
                    '      tMouse.LbDown = 1
                    '      tFlags.MouseClk = 0
                    '    ELSE
                    '      tMouse.LbDown = 0
                    '      tFlags.MouseClk = 1
                    '    END IF
                    END SELECT
                    
                    FUNCTION = CallWindowProc(OrigProc, Hndl, CBMSG, CBWPARAM, CBLPARAM)
                    END FUNCTION
                    
                    '--------------------------------------------------
                    '--------------------------------------------------
                    FUNCTION Az(BYVAL X1 AS SINGLE, BYVAL Y1 AS SINGLE, _
                                BYVAL X2 AS SINGLE, BYVAL Y2 AS SINGLE) AS SINGLE
                    
                    LOCAL Deg AS SINGLE
                    LOCAL X   AS SINGLE
                    LOCAL Y   AS SINGLE
                    
                    Deg! = 180 / (4 * ATN(1))
                    X! = X2 - X1
                    Y! = Y2 - Y1
                    
                    SELECT CASE Y!
                      CASE IS < 0.0!
                        Az! = -ATN(X! / Y!) * Deg!
                        IF X! < 0.0! THEN Az! = 360.0! - ATN(X! / Y!) * Deg!
                    
                      CASE IS > 0.0!
                        Az! = 180.0! - ATN(X! / Y!) * Deg!
                    
                      CASE IS 0.0!
                        IF X! > 0.0! THEN Az! = 90.0!
                        IF X! < 0.0! THEN Az! = 270.0!
                    END SELECT
                    
                    END FUNCTION
                    
                    '---------------------------------------------------------
                    '---------------------------------------------------------
                    
                    CALLBACK FUNCTION ObjMnu_CB()
                    
                    
                    IF CBMSG = %WM_COMMAND THEN
                      IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                    
                        SELECT CASE CBCTL
                          CASE %MNU_WINDING
                            IF tFlags.Winding = 1 THEN
                              tFlags.Winding = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_UNCHECKED OR %MF_ENABLED
                            ELSE
                              tFlags.Winding = 1
                              MENU SET STATE MnuHndl, BYCMD %MNU_WINDING, %MF_CHECKED OR %MF_ENABLED
                            END IF
                    
                          CASE %MNU_CULL_SURF
                            IF tFlags.Surf = 1 THEN
                              tFlags.Surf= 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_UNCHECKED OR %MF_ENABLED
                            ELSE
                              tFlags.Surf = 1
                              MENU SET STATE MnuHndl, BYCMD %MNU_CULL_SURF, %MF_CHECKED OR %MF_ENABLED
                            END IF
                    
                          CASE %MNU_DEPTH_TEST
                            IF tFlags.Test = 1 THEN
                              tFlags.Test = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_UNCHECKED OR %MF_ENABLED
                            ELSE
                              tFlags.Test = 1
                              MENU SET STATE MnuHndl, BYCMD %MNU_DEPTH_TEST, %MF_CHECKED OR %MF_ENABLED
                            END IF
                    
                          CASE %MNU_BACKSIDE
                            IF tFlags.Back THEN
                              tFlags.Back = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                              EXIT SELECT
                            END IF
                            tFlags.Back = 1
                            tFlags.Front = 0
                            tFlags.Both = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_CHECKED OR %MF_ENABLED
                            MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                            MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                    
                          CASE %MNU_FRONTSIDE
                            IF tFlags.Front THEN
                              tFlags.Front = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                              EXIT SELECT
                            END IF
                            tFlags.Back = 0
                            tFlags.Front = 1
                            tFlags.Both = 0
                            MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                            MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_CHECKED OR %MF_ENABLED
                            MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                    
                          CASE %MNU_BOTH
                            IF tFlags.Both THEN
                              tFlags.Both = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_UNCHECKED OR %MF_ENABLED
                              EXIT SELECT
                            END IF
                            tFlags.Back = 0
                            tFlags.Front = 0
                            tFlags.Both = 1
                            MENU SET STATE MnuHndl, BYCMD %MNU_BACKSIDE, %MF_UNCHECKED OR %MF_ENABLED
                            MENU SET STATE MnuHndl, BYCMD %MNU_FRONTSIDE, %MF_UNCHECKED OR %MF_ENABLED
                            MENU SET STATE MnuHndl, BYCMD %MNU_BOTH, %MF_CHECKED OR %MF_ENABLED
                    
                          CASE %MNU_TRANS
                            IF tFlags.Trans THEN
                              MENU SET STATE MnuHndl, BYCMD %MNU_TRANS, %MF_UNCHECKED OR %MF_ENABLED
                              tFlags.Trans = 0
                              EXIT SELECT
                            END IF
                            tFlags.Trans = 1
                            MENU SET STATE MnuHndl, BYCMD %MNU_TRANS, %MF_CHECKED OR %MF_ENABLED
                    
                          CASE %MNU_FLATCLR
                            IF tFlags.FlatClr THEN
                              MENU SET STATE MnuHndl, BYCMD %MNU_FLATCLR, %MF_UNCHECKED OR %MF_ENABLED
                              tFlags.FlatClr = 0
                              EXIT SELECT
                            END IF
                            tFlags.FlatClr = 1
                            MENU SET STATE MnuHndl, BYCMD %MNU_FLATCLR, %MF_CHECKED OR %MF_ENABLED
                    
                        END SELECT
                      END IF
                    END IF
                    END FUNCTION
                    '---------------------------------------------------------------
                    '---------------------------------------------------------------
                    Walt Decker

                    Comment


                    • #11
                      More &quot;Z&quot; Factor and Rotation

                      Given a polygon viewed from the edge, with each point having 0 (zero) for its "Z" factor, nothing is displayed. Further, it can't be rotated around any axis. For example, given a triangle with the coordinates:

                      -10, -15, 0
                      0, -15, 0
                      10, -15, 0

                      nothing is displayed no matter how the triangle is rotated. However, if we add a "Z" value to one of the coordinates, it can then be rotated in any direction.

                      Further, in OpenGL, as in most 3D systems, all objects can have a "Z" factor. This includes, points and lines. The following example points this out. It creates a flat terrain giving you the option of using points, lines, or quads to view the surface. In each display mode you have the option of rotating around the X or Y axis to see how each mode behaves.

                      In point mode, the surface is crisp and clear. In line mode the surface becomes a little fuzzy, and in quad mode it becomes more so. When rotated, however, each mode mode is crisp. I suspician that the fuzziness in the flat surface view is caused by the closeness of the points.

                      If you look at the code you will see that there is no RANDOMIZE (seed) statement. I left it out so that each time the example is run, the terrain would be the same.

                      Anyway, the code follows:
                      Code:
                      '=======================================================================
                      '                            OPENGL FUNCTIONS USED
                      '=======================================================================
                      ' glViewport()
                      ' glMatrixMode()
                      ' glLoadIdentity
                      ' glOrtho()
                      ' glclear()
                      ' glPushMatrix
                      ' glTranslatef()
                      ' glColor3Ub()
                      ' glBegin()
                      ' glEnd
                      ' glVertex3F()
                      ' glPopMatrix
                      ' glEnable()
                      ' glDisable()
                      ' glFlush
                      ' glFinish
                      ' glShadeModel()
                      '=========================================================================
                      '                            WINDOWS FUNCTIONS USED
                      '=========================================================================
                      ' GetDc
                      ' ReleaseDc
                      ' ChoosePixelFormat
                      ' SetPixelFormat
                      ' wglCreateContext
                      ' wglMakeCurrent
                      ' wglDeleteContext
                      ' SetWindowLong
                      '=========================================================================
                      
                      #COMPILE EXE
                      
                      DEFLNG A - Z
                      
                      #INCLUDE "WIN32API.INC"
                      #INCLUDE "gl.inc"
                      #INCLUDE "glu.inc"
                      
                      
                      TYPE Color_STRUCT
                        R AS BYTE
                        G AS BYTE
                        B AS BYTE
                      END TYPE
                      
                      TYPE Samp_STRUCT
                        X   AS SINGLE
                        Y   AS SINGLE
                        Elv AS SINGLE
                      END TYPE
                      
                      TYPE Menu_STRUCT
                        Points  AS BIT * 1 IN BYTE
                        LINES   AS BIT * 1
                        Quads   AS BIT * 1
                        RotateX AS BIT * 1
                        RotateY AS BIT * 1
                        Example AS BIT * 1
                      END TYPE
                      
                      TYPE OglFlag_STRUCT
                        EndProg     AS BIT * 1 IN BYTE
                        MouseClk    AS BIT * 1
                        OglBtnDead  AS BIT * 1
                        RunGlDemo   AS BIT * 1
                        Menu_STRUCT
                      END TYPE
                      
                      TYPE Button_STRUCT
                        LbDown AS BIT * 1 IN BYTE
                        LbClk  AS BIT * 1
                        RbDown AS BIT * 1
                        RbClk  AS BIT * 1
                      END TYPE
                      
                      TYPE Single2_STRUCT
                        Mx  AS SINGLE
                        My  AS SINGLE
                      END TYPE
                      
                      TYPE Mouse_STRUCT
                        Single2_STRUCT
                        Button_STRUCT
                      END TYPE
                      
                      %GFX_WIN     =    5
                      %BTN_END     =    6
                      %BTN_OGL     =    7
                      
                      %MNU_POINTS  =   50
                      %MNU_LINES   =   51
                      %MNU_QUADS   =   52
                      %MNU_ROTATE  =   53
                      %MNU_ROTATEX =   54
                      %MNU_ROTATEY =   55
                      %MNU_EXAMPLES =  56
                      
                      $WORLD = "World.Dat"
                      $KOLOR = "World.Clr"
                      
                      %OGL_ERROR   = %WM_USER + 500
                      %DLG_MESS    = %WM_USER + 600
                      
                      GLOBAL tFlags AS OglFlag_STRUCT
                      GLOBAL tMouse AS Mouse_STRUCT
                      
                      GLOBAL MnuHndl AS DWORD
                      
                      DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                      DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
                      DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                                  GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                      
                      DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                              BYVAL GfxHndl AS DWORD)
                      
                      DECLARE SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                      
                      
                      DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                                  tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                      
                      
                      DECLARE FUNCTION PBMAIN() AS LONG
                      DECLARE CALLBACK FUNCTION Main_CB()
                      
                      FUNCTION PBMAIN()
                      
                      LOCAL hDlg        AS DWORD
                      LOCAL ChildHndl   AS DWORD
                      LOCAL ChildHndl2  AS DWORD
                      
                      DIALOG NEW 0, "", , , 201, 131, _
                                              %WS_POPUP OR %WS_BORDER _
                                              OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                              %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                              %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                              %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                      
                      CONTROL ADD GRAPHIC, hDlg, %GFX_WIN, "", 5, 5, 190, 80, _
                                                               %SS_SUNKEN OR %SS_NOTIFY OR %WS_CHILD OR _
                                                              %WS_VISIBLE
                      
                      CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 95, 85, 20, %WS_CHILD _
                        OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                        %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                        %WS_EX_LTRREADING
                      
                      CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl Demo", 120, 95, 75, 20, _
                        %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                        OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                        %WS_EX_LTRREADING
                      
                      MENU NEW BAR TO MnuHndl
                      MENU NEW POPUP TO ChildHndl
                      MENU ADD POPUP, MnuHndl, "OGL Image Parameters", ChildHndl, %MF_ENABLED
                      
                        MENU ADD STRING, ChildHndl, "Points", %MNU_POINTS, %MF_ENABLED OR %MF_CHECKED, _
                                                     CALL ObjMnu_CB
                      
                        MENU ADD STRING, ChildHndl, "Lines", %MNU_LINES, %MF_ENABLED, _
                                                     CALL ObjMnu_CB
                        MENU ADD STRING, ChildHndl, "Quads", %MNU_QUADS, %MF_ENABLED, _
                                                     CALL ObjMnu_CB
                        MENU NEW POPUP TO ChildHndl_2
                        MENU ADD POPUP, ChildHndl, "Rotate", ChildHndl_2, %MF_ENABLED
                          MENU ADD STRING, ChildHndl_2, "Around X Axsis", %MNU_ROTATEX, %MF_ENABLED, _
                                                     CALL ObjMnu_CB
                          MENU ADD STRING, ChildHndl_2, "Around Y Axsis", %MNU_ROTATEY, %MF_ENABLED, _
                                                     CALL ObjMnu_CB
                        MENU ADD STRING, MnuHndl, "Example", %MNU_EXAMPLES, %MF_ENABLED, _
                                                     CALL ObjMnu_CB
                      
                      MENU ATTACH MnuHndl, hDlg
                      
                      DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
                      
                      tFlags.Points = 1
                      
                      DIALOG SHOW MODAL hDlg, CALL Main_CB
                      
                      IF DIR$($WORLD) <> "" THEN
                        KILL $WORLD
                        KILL $KOLOR
                      END IF
                      
                      END FUNCTION
                      
                      '------------------------------------------------------------
                      '------------------------------------------------------------
                      
                      CALLBACK FUNCTION Main_CB()
                      
                      LOCAL lParam AS LONG
                      LOCAL wParam AS LONG
                      
                      SELECT CASE AS LONG CBMSG
                      
                        wParam = CBWPARAM
                        CASE %WM_INITDIALOG
                          DIALOG POST CBHNDL, %DLG_MESS, 0, 0
                        CASE %WM_COMMAND
                          wParam = CBCTLMSG
                          SELECT CASE AS LONG wParam
                            CASE %BN_CLICKED, %STN_CLICKED, 1
                              SELECT CASE AS LONG CBCTL
                                CASE %GFX_WIN
                      
                                CASE %BTN_END
                                  tFlags.EndProg = 1
                                  CALL RunOgl(CBHNDL)
                                  DIALOG END CBHNDL
                                  FUNCTION = 1
                                  EXIT FUNCTION
                      
                                CASE %BTN_OGL
                                  tFlags.RunGlDemo = 1
                                  CALL RunOgl(CBHNDL)
                                  tFlags.RunGlDemo = 0
                                  FUNCTION = 1
                                  EXIT FUNCTION
                      
                              END SELECT
                          END SELECT
                      
                        CASE %WM_DESTROY
                          IF tFlags.EndProg THEN EXIT SELECT
                          tFlags.EndProg = 1
                          CALL RunOgl(CBHNDL)
                      
                        CASE %OGL_ERROR
                          SELECT CASE wParam
                            CASE 1
                              MSGBOX "Could not find matching pixel format"
                            CASE 2
                              MSGBOX "Could not set selected pixel format"
                            CASE 3
                              MSGBOX "Could not create rendering context"
                            CASE 4
                              MSGBOX "Could not make rendering context current.  Defined window may not" _
                                     + " support it"
                          END SELECT
                          DIALOG END CBHNDL
                      
                        CASE %DLG_MESS
                          CALL PreProcess(CBHNDL)
                          DIALOG SET TEXT CBHNDL, "Exploring Ogl: Z-Points"
                          GRAPHIC ATTACH CBHNDL, %GFX_WIN
                          GRAPHIC PRINT "Select 'Run Ogl Demo' button"
                          GRAPHIC SET POS (0, 8)
                          GRAPHIC PRINT "RotateX: Hold right mouse button down; move up and down"
                          GRAPHIC SET POS (0, 16)
                          GRAPHIC PRINT "RotateY: Hold right mouse button down; move left and right"
                          GRAPHIC SET POS (0, 32)
                          GRAPHIC PRINT "Right-click to exit while in rotation mode"
                          GRAPHIC DETACH
                          FUNCTION = 1
                      END SELECT
                      
                      END FUNCTION
                      
                      '------------------------------------------------------------
                      '------------------------------------------------------------
                      
                      SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR)
                      
                      '==============================================================
                      ' This is the 1st step in setting up windows for OpenGl support
                      ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
                      ' graphics
                      '==============================================================
                      
                      pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
                      pfd.nversion = 1
                      pfd.dwflags = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
                      pfd.dwlayermask = %PFD_MAIN_PLANE
                      pfd.ipixeltype = %PFD_TYPE_RGBA
                      pfd.ccolorbits = 24
                      pfd.cdepthbits = 24
                      pfd.caccumbits = 0
                      pfd.cstencilbits = 0
                      
                      END SUB
                      
                      '---------------------------------------------------------------
                      '---------------------------------------------------------------
                      
                      SUB RunOgl(BYVAL Hndl AS DWORD)
                      
                      STATIC Wide  AS LONG
                      STATIC High  AS LONG
                      
                      STATIC TileWide AS LONG
                      STATIC TileHigh AS LONG
                      
                      STATIC Lcx      AS SINGLE
                      STATIC Lcy      AS SINGLE
                      STATIC AziX     AS SINGLE
                      STATIC AziY     AS SINGLE
                      
                      LOCAL Offs AS SINGLE
                      
                      LOCAL ClearClr AS DWORD
                      
                      STATIC GfxDC     AS DWORD
                      STATIC OglRc     AS DWORD
                      STATIC GfxHndl   AS DWORD
                      
                      STATIC tPal() AS Color_STRUCT
                      STATIC tMap() AS Samp_STRUCT
                      
                      LOCAL tPixFmt AS PIXELFORMATDESCRIPTOR
                      
                      IF ISFALSE(GfxDc) THEN
                        IF tFlags.EndProg THEN EXIT SUB
                      
                        CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                        CALL OglPixFormat(tPixFmt)
                      
                        OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
                      
                        IF OglRc = 0 THEN EXIT SUB
                      
                        CALL SetOglWindow(Wide, High, 100)
                      ELSE
                        IF tFlags.EndProg THEN
                          CALL CloseOpenGL(OglRc, GfxDc, GfxHndl)
                          GfxDc = 0
                          EXIT SUB
                        END IF
                      END IF
                      
                      IF tFlags.Example THEN
                        CALL Example(Hndl, GfxDc)
                        EXIT SUB
                      END IF
                      
                      IF tFlags.MouseClk THEN
                        OPEN $WORLD FOR BINARY AS #1
                        OPEN $KOLOR FOR BINARY AS #2
                        GET #1, , TileHigh
                        GET #1, , TileWide
                      
                        DIM tPal(TileHigh, TileWide)
                        DIM tMap(TileHigh, TileWide)
                      
                        FOR I = 0 TO TileHigh
                          FOR J = 0 TO TileWide
                            GET #1, , tMap(I, J)
                            GET #2, , tPal(I, J)
                          NEXT J
                        NEXT I
                        CLOSE
                        EXIT SUB
                      END IF
                      
                      IF tFlags.RunGlDemo THEN
                      
                        ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                   %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                      
                        glEnable(%GL_DEPTH_TEST)
                      
                        IF tFlags.RotateX OR tFlags.RotateY THEN
                          Offs! = -0.5!
                          Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, CODEPTR(Mouse_SubCB))
                          CONTROL SET USER Hndl, %GFX_WIN, 1, Proc
                          DO
                            DIALOG DOEVENTS
                            IF tFlags.EndProg THEN EXIT DO
                      
                            IF tMouse.RbDown THEN
                              RESET tMouse
                              EXIT DO
                            END IF
                      
                            IF tMouse.LbDown THEN
                              DO
                                CALL Mouse(GfxHndl, 0)
                      
                                IF tFlags.RotateX THEN
                                  IF tMouse.My <> Lcy! THEN
                                    AziY! = AziY! + Lcy! - tMouse.My
                                    Lcy! = tMouse.My
                                    IF AziX! THEN AziX! = 0.0!
                                  ELSEIF tMouse.My = Lcy! THEN
                                    ITERATE DO
                                  END IF
                                END IF
                      
                                IF tFlags.RotateY THEN
                                  IF tMouse.Mx <> Lcx! THEN
                                    AziX! = AziX! + Lcx! - tMouse.Mx
                                    Lcx! = tMouse.Mx
                                  ELSEIF tMouse.Mx = Lcx! THEN
                                    ITERATE DO
                                  END IF
                                END IF
                      
                                IF tFlags.Points THEN CALL OglPoints(TileHigh, TileWide, tMap(), tPal(), AziX!, AziY!)
                                IF tFlags.Lines THEN CALL OglLines(TileHigh, TileWide, tMap(), tPal(), AziX!, AziY!)
                                IF tFlags.Quads THEN CALL OglQuads(TileHigh, TileWide, tMap(), tPal(), AziX!, AziY!)
                                SwapBuffers(GfxDc)
                                glFlush
                                glClear(ClearClr)
                                DIALOG DOEVENTS
                              LOOP UNTIL tMouse.LbDown = 0
                      
                              IF tMouse.RbDown THEN
                                RESET tMouse
                                EXIT DO
                              END IF
                            END IF
                            RESET tMouse
                          LOOP
                      
                          Proc = SetWindowLong(GfxHndl, %GWL_WNDPROC, Proc)
                          CONTROL SET USER Hndl, %GFX_WIN, 1, 0
                        ELSE
                          IF tFlags.Points THEN CALL OglPoints(TileHigh, TileWide, tMap(), tPal(), AziX!, AziY!)
                          IF tFlags.Lines THEN CALL OglLines(TileHigh, TileWide, tMap(), tPal(), AziX!, AziY!)
                          IF tFlags.Quads THEN CALL OglQuads(TileHigh, TileWide, tMap(), tPal(), AziX!, AziY!)
                          SwapBuffers(GfxDc)
                          glFlush
                        END IF
                        glDisable(%GL_DEPTH_TEST)
                        glFinish
                      
                        glClear(ClearClr)
                      END IF
                      
                      END SUB
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                          tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                      
                      '================================================================
                      '  This is the second step for OpenGL support
                      '  ChoosePixelFormat selects a pixel format that matches that
                      '  described in the PIXELFORMATDESCRIPTOR structure.
                      '
                      '  Each step in the setup is quried because not all windows support
                      '  OpenGL rendering
                      '================================================================
                      
                      LOCAL PixFormat AS DWORD
                      LOCAL OglRc     AS DWORD
                      
                      LOCAL T AS LONG
                      
                      PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
                      
                      IF ISFALSE (PixFormat) THEN
                        DIALOG POST Hndl, %OGL_ERROR, 1, 0
                        EXIT FUNCTION
                      END IF
                      
                      t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
                      
                      IF ISFALSE(t) THEN
                        DIALOG POST Hndl, %OGL_ERROR, 2, 0
                        EXIT FUNCTION
                      END IF
                      
                      OglRc = wglCreateContext(GfxDc)
                      
                      IF ISFALSE(OglRc) THEN
                        DIALOG POST Hndl, %OGL_ERROR, 3, 0
                        EXIT FUNCTION
                      END IF
                      
                      t = wglMakeCurrent(GfxDc, OglRc)
                      
                      IF ISFALSE(t) THEN
                        DIALOG POST Hndl, %OGL_ERROR, 4, 0
                        EXIT FUNCTION
                      END IF
                      
                      SetOglPipe = OglRc
                      END FUNCTION
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                       BYVAL OrthoRange AS LONG)
                      
                      LOCAL ClearClr AS DWORD
                      
                      LOCAL Aspect AS SINGLE
                      LOCAL Xmin   AS SINGLE
                      LOCAL Ymin   AS SINGLE
                      LOCAL Xmax   AS SINGLE
                      LOCAL Ymax   AS SINGLE
                      LOCAL Zmin   AS SINGLE
                      LOCAL Zmax   AS SINGLE
                      
                      '=================================================================
                      ' This defines the graphics environment.
                      ' Getting this correct is crucial to using OpenGL.
                      '
                      ' In previous examples the orthographic projection was set to the
                      ' window coordinates.  This now changes the projection coordinates
                      ' to something other than the window coordinates.
                      '=================================================================
                      
                      ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                 %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                      
                      IF Wide <= High THEN
                        Aspect! = High / Wide
                      ELSE
                        Aspect! = Wide / High
                      END IF
                      
                      IF Wide <= High THEN
                        Xmin! = -OrthoRange / 2
                        Xmax! = OrthoRange  / 2
                        Ymin! = (-OrthoRange / 2) * Aspect!
                        Ymax! = (OrthoRange / 2) * Aspect!
                      ELSE
                        Xmin! = (-OrthoRange / 2) * Aspect!
                        Xmax! = (OrthoRange / 2) * Aspect!
                        Ymin! = (-OrthoRange / 2)
                        Ymax! = (OrthoRange  / 2)
                      END IF
                      
                      Zmin! = -OrthoRange / 2
                      Zmax! = OrthoRange
                      
                      glViewport(0, 0, Wide, High)
                      glMatrixMode(%GL_PROJECTION)
                      glLoadIdentity
                      glOrtho(Xmin!, Xmax!, Ymin!, Ymax!, Zmin!, Zmax!)
                      glMatrixMode(%GL_MODELVIEW)
                      glLoadIdentity
                      glClear(ClearClr)
                      
                      END SUB
                      
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
                      
                      wglMakeCurrent(0, 0)
                      wglDeleteContext(OglRc)
                      ReleaseDc(GfxHndl,GfxDc)
                      
                      END SUB
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                          GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                      
                      CONTROL HANDLE Hndl, %GFX_WIN TO GfxHndl
                      CONTROL GET CLIENT Hndl, %GFX_WIN TO Wide, High
                      DIALOG UNITS Hndl, Wide, High TO PIXELS Wide, High
                      
                      GfxDc = GetDc(GfxHndl)
                      
                      END SUB
                      
                      '-----------------------------------------------------------------
                      '-----------------------------------------------------------------
                      
                      SUB Mouse(BYVAL GfxHndl AS DWORD, BYVAL Hndl AS DWORD)
                      
                      LOCAL tPoint AS POINT
                      
                      GetCursorPos(tPoint)
                      ScreenToClient(GfxHndl, tPoint)
                      
                      tMouse.Mx = tPoint.X
                      tMouse.My = tPoint.Y
                      
                      END SUB
                      
                      '-------------------------------------------------------------------
                      '-------------------------------------------------------------------
                      
                      SUB WindowToProjection(X AS DOUBLE, Y AS DOUBLE, Z AS DOUBLE)
                      
                      '============================================================
                      ' Since the orthographic coordinate system does not reflect
                      ' the window coordinate system, the window coordinate system
                      ' is translated to the ortho system by gluUnProject().
                      '
                      ' That OpenGL function uses the window values and the values
                      ' stored in the viewport matrix, the modle matrix and the
                      ' projection matrix to calculate the ortho coordinates.  This
                      ' routine can also be used to calculate the perspective view
                      ' coordinates.
                      '
                      ' Because OpenGL uses the various matricies for it's calculations
                      ' we have to get those matricies before calling gluUnProject().
                      ' That's what the various forms of glGet...() do.  Along with
                      ' our window coordinates we pass those matricies to gluUnProject()
                      ' and it returns the OGL coordinates in the last three parameters:
                      ' WinX, WinY, WinZ.
                      '============================================================
                      
                      LOCAL WinViewport()   AS LONG
                      LOCAL ModleMatrix()   AS DOUBLE
                      LOCAL ProjectMatrix() AS DOUBLE
                      
                      LOCAL WinX AS DOUBLE
                      LOCAL WinY AS DOUBLE
                      LOCAL WinZ AS DOUBLE
                      
                      DIM WinViewPort(0 TO 1, 0 TO 1)    '<--- 4 element array
                      DIM ModleMatrix(0 TO 3, 0 TO 3)    '<--- 16 element array
                      DIM ProjectMatrix(0 TO 3, 0 TO 3)
                      
                      glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
                      glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
                      glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
                      
                      gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
                      
                      X = WinX
                      Y = WinY
                      Z = WinZ
                      
                      END SUB
                      
                      '--------------------------------------------------------
                      '--------------------------------------------------------
                      
                      CALLBACK FUNCTION Mouse_SubCB
                      
                      LOCAL Hndl      AS DWORD
                      LOCAL OrigProc  AS DWORD
                      LOCAL Gfx_Hndl  AS DWORD
                      
                      Hndl = CBHNDL
                      Gfx_Hndl = GetDlgCtrlId(Hndl)
                      OrigProc = GetParent(Hndl)
                      CONTROL GET USER OrigProc, Gfx_Hndl, 1 TO OrigProc
                      IF OrigProc = 0 THEN EXIT FUNCTION
                      
                      SELECT CASE CBMSG
                        CASE IS %WM_LBUTTONDOWN
                          tMouse.LbDown = 1
                          tmouse.LbClk = 0
                          FUNCTION = 1
                          EXIT FUNCTION
                      
                        CASE IS %WM_LBUTTONUP
                          tMouse.LbDown = 0
                          tMouse.LbClk = 1
                          FUNCTION = 1
                          EXIT FUNCTION
                      
                        CASE IS %WM_RBUTTONDOWN
                          tMouse.RbDown = 1
                          FUNCTION = 1
                          EXIT FUNCTION
                      
                        CASE IS %WM_RBUTTONUP
                          FUNCTION = 1
                          EXIT FUNCTION
                      
                      END SELECT
                      
                      FUNCTION = CallWindowProc(OrigProc, Hndl, CBMSG, CBWPARAM, CBLPARAM)
                      END FUNCTION
                      
                      '--------------------------------------------------
                      '--------------------------------------------------
                      FUNCTION Az(BYVAL X1 AS SINGLE, BYVAL Y1 AS SINGLE, _
                                  BYVAL X2 AS SINGLE, BYVAL Y2 AS SINGLE) AS SINGLE
                      
                      '=============================================================
                      ' Calculates the compass direction from one point to another.
                      ' The direction is calculated in a clock-wise direction with
                      ' 0 (zero)/360 at the top and 180 at the bottom
                      ' X1, Y1 is the point from
                      ' X2, Y2 is the point to
                      ' Az is returned in degrees from 0 to < 360
                      '=============================================================
                      
                      LOCAL Deg AS SINGLE
                      LOCAL X   AS SINGLE
                      LOCAL Y   AS SINGLE
                      
                      Deg! = 180 / (4 * ATN(1))
                      X! = X2 - X1
                      Y! = Y2 - Y1
                      
                      SELECT CASE Y!
                        CASE IS < 0.0!
                          Az! = -ATN(X! / Y!) * Deg!
                          IF X! < 0.0! THEN Az! = 360.0! - ATN(X! / Y!) * Deg!
                      
                        CASE IS > 0.0!
                          Az! = 180.0! - ATN(X! / Y!) * Deg!
                      
                        CASE IS 0.0!
                          IF X! > 0.0! THEN Az! = 90.0!
                          IF X! < 0.0! THEN Az! = 270.0!
                      END SELECT
                      
                      END FUNCTION
                      
                      '-----------------------------------------------------
                      '-----------------------------------------------------
                      
                      SUB PreProcess(Hndl)
                        DIALOG DOEVENTS
                        IF DIR$($WORLD) <> "" THEN
                          KILL $WORLD
                          KILL $KOLOR
                        END IF
                        DIALOG SET TEXT Hndl, "Processing. Please wait."
                        DIALOG DOEVENTS
                        CALL MakeIslands(128, 300, Hndl)
                      
                      END SUB
                      
                      '-----------------------------------------------------
                      '-----------------------------------------------------
                      
                      SUB InitMap(BYVAL High AS LONG, BYVAL Wide AS LONG, BYVAL Rlow AS LONG, _
                                  BYVAL Rhigh AS LONG, Map() AS SINGLE)
                      
                      '========== Produces random values for each point in array Map() =========
                      
                      LOCAL RandNum AS SINGLE
                      
                      LOCAL COUNT AS BYTE
                      
                      FOR I = 0 TO High
                        FOR J = 0 TO Wide
                          IF COUNT <= 0 THEN
                            COUNT = RND(1, 10)
                            RandNum = RND(Rlow, Rhigh)
                          END IF
                          Map(I, J) = RandNum
                          DECR COUNT
                        NEXT J
                      NEXT I
                      
                      END SUB
                      
                      '-----------------------------------------------------
                      '-----------------------------------------------------
                      
                      SUB MakeIslands(BYVAL TileHigh AS LONG, BYVAL Tilewide AS LONG, BYVAL Hndl AS DWORD)
                      
                      LOCAL MinElv AS SINGLE
                      LOCAL MaxElv AS SINGLE
                      LOCAL CkElv  AS SINGLE
                      LOCAL Value AS SINGLE
                      
                      LOCAL Amap() AS SINGLE
                      
                      LOCAL X AS DOUBLE
                      LOCAL Y AS DOUBLE
                      
                      LOCAL IslPoints() AS LONG
                      
                      LOCAL NumSamp     AS LONG
                      LOCAL Cx          AS LONG
                      LOCAL Cy          AS LONG
                      
                      LOCAL tSamp() AS Samp_STRUCT
                      LOCAL tPal()  AS Color_STRUCT
                      
                      DIALOG DOEVENTS
                      DIALOG DOEVENTS
                      
                      NumSamp = MAX(TileHigh, TileWide) * 1.5
                      Cx = TileWide \ 2
                      Cy = TileHigh \ 2
                      MinElv = 1
                      MaxElv = 50
                      CkElv = 0
                      
                      Value = 0.0
                      
                      DIM Amap(TileHigh, TileWide)
                      DIM tPal(TileHigh, TileWide)
                      DIM tSamp(1 TO NumSamp)
                      DIM IslPoints(13, 2)
                      
                      CALL InitMap(TileHigh, TileWide, -10, -1, Amap())
                      
                      RandStart = RND(0, 360)
                      RandStep = RND(1, 4)
                      
                      IF RandStep = 1 THEN RandStep = 30
                      IF RandStep = 2 THEN RandStep = 45
                      IF RandStep = 3 THEN RandStep = 60
                      IF RandStep = 4 THEN RandStep = 90
                      
                      CALL LandPoints(Cx, Cy, TileHigh, TileWide, RandStart, RandStep, Bcount, IslPoints(), _
                                  Amap(), Value)
                      CALL ColorFill(Cx, Cy, 0, 0, TileWide, TileHigh, MinElv, MaxElv, CkElv, Amap())
                      CALL TakeMapSamp(TileHigh, TileWide, NumSamp, tSamp(), Amap())
                      CALL Contour(TileHigh, TileWide, NumSamp, tSamp(), Amap())
                      CALL GenColors(TileHigh, TileWide, Amap(), tPal())
                      
                      CALL RunOgl(Hndl)
                      
                      REDIM tSamp(0)
                      
                      OPEN $WORLD FOR BINARY AS #1
                      OPEN $KOLOR FOR BINARY AS #2
                      
                      PUT #1, , TileHigh
                      PUT #1, , TileWide
                      
                      FOR I = 0 TO TileHigh
                        FOR J = 0 TO TileWide
                          X = J
                          Y = I
                          CALL WindowToProjection(X, Y, 0)
                          tSamp(0).X = X
                          tSamp(0).Y = Y
                          tSamp(0).Elv = Amap(I, J)
                          PUT #1, , tSamp(0)
                          PUT #2, , tPal(I, J)
                        NEXT J
                      NEXT I
                      CLOSE
                      tFlags.EndProg = 1
                      CALL RunOgl(Hndl)
                      tFlags.EndProg = 0
                      tFlags.MouseClk = 1
                      CALL RunOgl(Hndl)
                      tFlags.MouseClk = 0
                      END SUB
                      
                      '----------------------------------------------------------
                      '----------------------------------------------------------
                      
                      SUB LandPoints(BYVAL Cx AS SINGLE, BYVAL Cy AS SINGLE, BYVAL High AS LONG, _
                                 BYVAL Wide AS LONG, BYVAL RndStart AS LONG, BYVAL RndStep AS LONG, _
                                 Bcount AS LONG, Buffer() AS LONG, Amap() AS SINGLE, _
                                 BYVAL Value AS SINGLE)
                      
                      '================================================================================
                      ' Produces the outline of a polygon by setting connection elements in
                      ' array Amap().
                      '
                      ' Cx, Cy = center of polygon
                      ' High, Wide = height and width of graphic
                      ' RndStart = starting angle of polygon
                      ' RndStep = size of each angle
                      ' Bcount = number of points in polygon
                      ' Buffer() = array to store polygon points and is set to Buffer(Rows, 2) where
                      '            the second dimension contains the X, Y coordinates of the polygon
                      ' Amap() = array in which to set Value (see Value)
                      ' Value = the value to set in Amap()
                      '================================================================================
                      
                      LOCAL Rad AS SINGLE
                      LOCAL X   AS SINGLE
                      LOCAL Y   AS SINGLE
                      LOCAL Lx  AS SINGLE
                      LOCAL Ly  AS SINGLE
                      LOCAL Azi AS SINGLE
                      
                      LOCAL Dist    AS LONG
                      LOCAL Counter AS LONG
                      LOCAL X1      AS LONG
                      LOCAL Y1      AS LONG
                      
                      Rad! = (4 * ATN(1)) / 180
                      
                      Lx! = 0
                      Ly! = 0
                      Counter = 0
                      Dist = MIN(Wide \ 2, High \ 2) * 0.75
                      
                      FOR I = RndStart TO 360 + RndStart - 1 STEP RndStep
                        Buffer(Counter, 0) = Cx + Dist * SIN(I * Rad!)
                        Buffer(Counter, 1) = Cy - Dist * COS(I * Rad!)
                        INCR Counter
                      NEXT I
                      
                      Buffer(Counter, 0) = Buffer(0, 0)
                      Buffer(Counter, 1) = Buffer(0, 1)
                      
                      FOR I = 1 TO Counter
                        X! = Buffer(I - 1, 0)
                        Y! = Buffer(I - 1, 1)
                        Lx! = Buffer(I, 0)
                        Ly! = Buffer(I, 1)
                        Dist = ((Lx! - X!) ^ 2 + (Ly! - Y!) ^ 2)
                        Dist = SQR(Dist)
                        Azi! = Az(X!, Y!, Lx!, Ly!)
                      
                        FOR J = 0 TO Dist
                          X1 = X + J * SIN(Azi * rad!)
                          Y1 = Y - J * COS(Azi * rad!)
                          Amap(Y1, X1) = Value
                        NEXT J
                      
                      NEXT I
                      
                      Bcount = Counter
                      
                      END SUB
                      
                      '--------------------------------------------------------------
                      '--------------------------------------------------------------
                      
                      SUB ColorFill(BYVAL Cx AS LONG, BYVAL Cy AS LONG, BYVAL MinX AS LONG, _
                                    BYVAL MinY AS LONG, BYVAL MaxX AS LONG, BYVAL MaxY AS LONG, _
                                    BYVAL MinElv AS LONG, BYVAL MaxElv AS LONG, BYVAL CkElv AS LONG, _
                                    Sb() AS SINGLE)
                      
                      '=============================================================
                      ' This is a modification of a 4-way flood fill.
                      ' It does not use recursion, but manages it's own stack via
                      ' functions mPush and mPop.
                      '
                      ' Cx, Cy = point where fill begins
                      ' MinX, MinY = minimum fill limits
                      ' MaxX, MaxY = maximum fill limits
                      ' MinElv = minimum elevation to use for filling
                      ' MaxElv = maximum elevation to use for filling
                      ' CkElv = elevation where filling is to stop
                      ' Sb() = array in which fill elevations are to be written
                      '
                      '=============================================================
                      
                      LOCAL mStackPointer AS LONG
                      LOCAL StackSize     AS LONG
                      
                      LOCAL mStack()     AS LONG
                      
                      LOCAL X         AS LONG    'Array column
                      LOCAL Y         AS LONG    'Array row
                      LOCAL ElevDat   AS LONG    'Elevation data, either + or -
                      LOCAL X1        AS LONG    'Array column
                      LOCAL Y1        AS LONG    'Array row
                      LOCAL Cntr      AS LONG    'Constant value compare
                      LOCAL Minus     AS LONG    'Elevation decrement factor
                      LOCAL Dist      AS LONG    'Incremental counter for # elevations written
                                                 'changed when > Cntr
                      LOCAL High      AS LONG    'Elevation to write; changed when < MinElv or
                                                 'when Dist > Cntr
                      LOCAL H         AS LONG    'Width of surface
                      LOCAL W         AS LONG    'Hight of surface
                      
                      High = RND(MinElv, MaxElv)
                      Minus = RND(4, 9)
                      
                      H = MaxY - MinY + 1
                      W = MaxX - MinX + 1
                      
                      StackSize = W * H + 1
                      
                      Dist = SQR((MaxX - Cx)^2 + (MaxY - Cy)^2)
                      Y = (MaxElv - MinElv + 1) \ Minus
                      Cntr = (MAX(Dist, Y) \ MIN(Dist, Y)) * (Minus * .5)
                      Dist = 0
                      
                      REDIM mStack(StackSize)
                      
                      X = Cx
                      Y = Cy
                      
                      Sb(Y, X) = High
                      
                      
                      CALL emptyStack(h, mStackPointer, StackSize, mStack())
                      
                      IF mPush(x, y, h, mStackPointer, StackSize, mStack()) THEN
                      
                        DO
                          IF mPop(x, y, h, mStackPointer, StackSize, mStack()) = 0 THEN EXIT DO
                          X1 = X - 1
                          IF (X1 >= MinX AND X1 <= W)  AND Y >= MinY THEN
                            ElevDat = Sb(Y, X1)
                            IF ElevDat < CkElv THEN
                              IF mPush(X1, Y, H, mStackPointer, StackSize, mStack()) = 0 THEN EXIT DO
                            END IF
                          END IF
                          X1 = X + 1
                          IF (X1 >= MinX  AND X1 <= W) THEN
                            ElevDat = Sb(Y, X1)
                            IF ElevDat < CkElv THEN
                              IF mPush(X1, Y, H, mStackPointer, StackSize, mStack()) = 0 THEN EXIT DO
                            END IF
                          END IF
                          Y1 = Y + 1
                          IF Y1 < h THEN
                            ElevDat = Sb(Y1, X)
                          END IF
                          IF Y1 < h AND ElevDat < CkElv THEN
                            IF mPush(X, Y1, H, mStackPointer, StackSize, mStack()) = 0 THEN EXIT DO
                          END IF
                          Y1 = Y - 1
                          IF Y1 >= MinY THEN
                            ElevDat = Sb(Y1, X)
                          END IF
                          IF Y1 >= MinY AND ElevDat < CkElv THEN
                            IF mPush(X, Y1, H, mStackPointer, StackSize, mStack()) = 0 THEN EXIT DO
                          END IF
                          IF Dist > Cntr THEN
                            High = High - Minus
                            Dist = 0
                            IF High < MinElv THEN High = RND(MinElv, MaxElv)
                          END IF
                          INCR Dist
                          IF High <= MinElv THEN
                            High = MaxElv
                          END IF
                          Sb(Y, X) = High
                        LOOP
                      END IF
                      END SUB
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      FUNCTION EmptyStack(h, mStackPointer, StackSize, mStack())
                      
                      '================ clears the stack for SUB ColorFill ============
                      
                      RESET mStack()
                      mStackPointer = -1
                      END FUNCTION
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      FUNCTION mPop(x, y, h, mStackPointer, StackSize, mStack()) AS LONG
                      
                      '============ removes a coordinate from the stack for ColorFill ===
                      
                      IF mStackPointer >= 0 THEN
                        p = mStack(mStackPointer)
                        x = p \ h
                        y = p MOD h
                        DECR mStackPointer
                        FUNCTION = 1
                      ELSE
                        FUNCTION = 0
                      END IF
                      
                      END FUNCTION
                      
                      '----------------------------------------------------------------
                      '----------------------------------------------------------------
                      
                      FUNCTION mPush(x, y, h , mStackPointer, StackSize, mStack()) AS LONG
                      
                      '============= saves a coordinate for SUB ColorFill ==============
                      IF mStackPointer < StackSize THEN
                        INCR mStackPointer
                        mStack(mStackPointer) = h * x + y
                        FUNCTION = 1
                      ELSE
                        FUNCTION = 0
                      END IF
                      
                      END FUNCTION
                      
                      '-----------------------------------------------------------------------------
                      '-----------------------------------------------------------------------------
                      
                      SUB TakeMapSamp(BYVAL High AS LONG, BYVAL Wide AS LONG, BYVAL Ih AS LONG, _
                                      tSamp() AS Samp_STRUCT, Tile() AS SINGLE)
                      
                      '=========== takes random samples from Tile() for use by SUB Contour =========
                      
                      LOCAL Row AS LONG
                      LOCAL Col AS LONG
                      
                      FOR I = 1 TO Ih
                        Row = RND(0, High)
                        Col = RND(0, Wide)
                        tSamp(I).Y = Row
                        tSamp(I).X = Col
                        tSamp(I).Elv = Tile(Row, Col)
                      NEXT I
                      
                      Eliminate_Dupes: '
                      
                      FOR I = 1 TO Ih
                        FOR J = I + 1 TO Ih
                          IF (tSamp(I).X = tSamp(J).X) AND (tSamp(I).Y = tSamp(J).Y) THEN
                            IF (tSamp(I).Elv <> tSamp(J).Elv) THEN
                              Row = RND(0, High)
                              Col = RND(0, Wide)
                              tSamp(I).Y = Row
                              tSamp(I).X = Col
                              tSamp(I).Elv = Tile(Row, Col)
                              GOTO Eliminate_Dupes
                            END IF
                          END IF
                        NEXT J
                      NEXT I
                      
                      END SUB
                      
                      '--------------------------------------------------------------------
                      '--------------------------------------------------------------------
                      
                      SUB Contour(BYVAL High, BYVAL Wide, BYVAL Ih, Cords() AS Samp_STRUCT, Amap() AS SINGLE)
                      
                      '====================================================================
                      ' This is a modification to a 20+ year old line printer contouring
                      ' package I wrote.  It's fairly fast but slows as the number of sampling
                      ' points increase.  It can use any sample data because it normalizes the
                      ' data points to the width and height of the Amap() array.
                      '
                      ' The algo uses grid-node and slope interpolation to calculate the
                      ' elevation at each point in the array.
                      '====================================================================
                      
                      LOCAL Dx1    AS SINGLE
                      LOCAL Dx2    AS SINGLE
                      LOCAL XX2    AS SINGLE
                      LOCAL XX1    AS SINGLE
                      LOCAL Small  AS SINGLE
                      LOCAL S1     AS SINGLE
                      LOCAL S2     AS SINGLE
                      LOCAL Dist() AS SINGLE
                      LOCAL D      AS SINGLE
                      
                      REDIM Dist(1 TO Ih)
                      
                      Dx1! = Wide / (Wide - 1)
                      Dx2! = High / (High - 1)
                      Small! = (Dx1 * Dx1 + Dx2 * Dx2) / 10000
                      
                      XX2! = 0
                      
                      FOR I = 0 TO High
                        XX1! = 0
                        FOR J = 0 TO Wide
                      
                          FOR K = 1 TO Ih
                            Dist!(K) = (XX1! - Cords(K).X) ^ 2 + (XX2! - Cords(K).Y) ^ 2
                          NEXT K
                      
                          S1! = 0.0
                          S2! = 0.0
                      
                          FOR L = 1 TO 4
                            Ic = 1
                            FOR M = 2 TO Ih
                              IF Dist!(M) < Dist!(Ic) THEN Ic = M
                            NEXT M
                            IF Dist!(Ic) < Small THEN GOTO Set_Amap
                            D! = SQR(Dist(Ic))
                            S1! = S1! + Cords(Ic).Elv / D
                            S2! = S2! + 1.0 / D
                            Dist!(Ic) = 9.0E+35
                          NEXT L
                          Amap(I, J) = S1! / S2!
                          GOTO Inc_XX1
                      Set_Amap: '
                          Amap(I, J) = Cords(Ic).Elv
                      Inc_XX1: '
                          XX1! = XX1! + Dx1!
                        NEXT J
                        XX2! = XX2! + Dx2!
                      NEXT I
                      
                      END SUB
                      
                      '-------------------------------------------------------------------
                      '-------------------------------------------------------------------
                      
                      SUB GenColors(BYVAL High, BYVAL Wide, Amap() AS SINGLE, tPal() AS Color_STRUCT)
                      
                      '======== Assigns a color for each elevation range in array Amap() ==========
                      
                      LOCAL Clr AS DWORD
                      
                      LOCAL ClrPtr AS BYTE POINTER
                      
                      ClrPtr = VARPTR(Clr)
                      
                      FOR I = 0 TO High
                        FOR J = 0 TO Wide
                          Clr = CINT(Amap(I, J))
                          SELECT CASE AS LONG clr
                            CASE IS < -10
                              Clr = 0
                            CASE -10 TO -6
                              Clr = RGB(0, RND(64, 196), RND(128, 255))
                            CASE -5 TO -1
                              Clr = RGB(RND(10, 100), RND(192, 255), RND(192, 255))
                            CASE 0 TO 4
                              Clr = RGB(RND(160, 225), RND(160, 225), RND(100, 190))
                            CASE 5 TO 9
                              Clr = RGB(RND(96, 128), RND(100, 200), RND(10, 96))
                            CASE 10 TO 14
                              Clr = RGB(RND(0, 10), RND(64, 225), RND(10, 96))
                            CASE 15 TO 19
                              Clr = RGB(RND(64, 128), RND(120, 225), RND(10, 64))
                            CASE 20 TO 24
                              Clr = RGB(RND(100, 128), RND(120, 255), RND(10, 64))
                            CASE 25 TO 29
                              clr = RGB(RND(128, 200), RND(128, 200), RND(10, 64))
                            CASE 30 TO 34
                              Clr = RGB(RND(164, 225), RND(164, 225), RND(10, 64))
                            CASE 35 TO 39
                              Clr = RGB(RND(100, 200), RND(64, 128), RND(1, 10))
                            CASE 40 TO 45
                              Clr = RGB(RND(186, 210), RND(186, 210), RND(196, 210))
                            CASE IS > 45
                              Clr = RGB(RND(200, 255), RND(200, 255), RND(200, 255))
                            CASE ELSE
                              Clr = RGB(RND(0, 255), RND(0, 255), RND(0, 255))
                          END SELECT
                          tPal(I, J).R = @ClrPtr[0]
                          tPal(I, J).G = @ClrPtr[1]
                          tPal(I, J).B = @ClrPtr[2]
                        NEXT J
                      NEXT I
                      END SUB
                      
                      '------------------------------------------------------------------
                      '------------------------------------------------------------------
                      
                      CALLBACK FUNCTION ObjMnu_CB()
                      
                      
                      IF CBMSG = %WM_COMMAND THEN
                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                      
                          SELECT CASE CBCTL
                            CASE %MNU_POINTS
                              IF tFlags.Points = 1 THEN
                                tFlags.Points = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_POINTS, %MF_UNCHECKED OR %MF_ENABLED
                                DIALOG SET TEXT CBHNDL, "Exploring Ogl"
                              ELSE
                                tFlags.Points = 1
                                tFlags.Lines = 0
                                tFlags.Quads = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_POINTS, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LINES, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_QUADS, %MF_UNCHECKED OR %MF_ENABLED
                                DIALOG SET TEXT CBHNDL, "Exploring Ogl: Z-Points"
                              END IF
                      
                            CASE %MNU_LINES
                              IF tFlags.Lines = 1 THEN
                                tFlags.Lines = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_LINES, %MF_UNCHECKED OR %MF_ENABLED
                                DIALOG SET TEXT CBHNDL, "Exploring Ogl"
                              ELSE
                                tFlags.Lines = 1
                                tFlags.Points = 0
                                tFlags.Quads = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_LINES, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_POINTS, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_QUADS, %MF_UNCHECKED OR %MF_ENABLED
                                DIALOG SET TEXT CBHNDL, "Exploring Ogl: Z-Lines"
                              END IF
                      
                            CASE %MNU_QUADS
                              IF tFlags.Quads = 1 THEN
                                tFlags.Quads = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_QUADS, %MF_UNCHECKED OR %MF_ENABLED
                                DIALOG SET TEXT CBHNDL, "Exploring Ogl"
                              ELSE
                                tFlags.Quads = 1
                                tFlags.Points = 0
                                tFlags.Lines = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_QUADS, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LINES, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_POINTS, %MF_UNCHECKED OR %MF_ENABLED
                                DIALOG SET TEXT CBHNDL, "Exploring Ogl: Z-Quads"
                              END IF
                      
                            CASE %MNU_ROTATEX
                              IF tFlags.RotateX THEN
                                tFlags.RotateX = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                                EXIT SELECT
                              END IF
                              tFlags.RotateX = 1
                              tFlags.RotateY = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_CHECKED OR %MF_ENABLED
                              MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                      
                            CASE %MNU_ROTATEY
                              IF tFlags.RotateY THEN
                                tFlags.RotateY = 0
                                MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                                EXIT SELECT
                              END IF
                              tFlags.RotateY = 1
                              tFlags.RotateX = 0
                              MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                              MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_CHECKED OR %MF_ENABLED
                      
                            CASE %MNU_EXAMPLES
                              IF tFlags.RunGlDemo THEN EXIT SELECT
                              tFlags.Example = 1
                              CALL RunOgl(CBHNDL)
                              tFlags.Example = 0
                          END SELECT
                        END IF
                      END IF
                      END FUNCTION
                      
                      '----------------------------------------------------------------------------
                      '----------------------------------------------------------------------------
                      
                      SUB OglPoints(BYVAL TileHigh AS LONG, BYVAL TileWide AS LONG, _
                                    tMap() AS Samp_STRUCT, tPal() AS Color_STRUCT, _
                                    BYVAL AziX AS SINGLE, BYVAL AziY AS SINGLE)
                      
                      glPushMatrix
                      
                      IF tFlags.RotateY THEN
                        glRotateF(AziX!, 0, .001, 0)
                        IF AziY! THEN glRotateF(AziY!, .001, 0, 0)
                      END IF
                      IF tFlags.RotateX THEN
                        glRotateF(AziY!, .001, 0, 0)
                        IF AziX! THEN glRotateF(AziX!, 0, .001, 0)
                      END IF
                      
                      glBegin(%GL_POINTS)
                        FOR I = 0 TO TileHigh
                          FOR J = 0 TO TileWide
                              glColor3Ub(tPal(I, J).R, tPal(I, J).G, tPal(I, J).B)
                              glVertex3F(tMap(I, J).X, tMap(I, J).Y, tMap(I, J).Elv)
                          NEXT J
                        NEXT I
                      glEnd
                      glPopMatrix
                      END SUB
                      
                      '-----------------------------------------------------------------------------
                      '-----------------------------------------------------------------------------
                      
                      SUB OglLines(BYVAL TileHigh AS LONG, BYVAL TileWide AS LONG, _
                                   tMap() AS Samp_STRUCT, tPal() AS Color_STRUCT, _
                                   BYVAL AziX AS SINGLE, AziY AS SINGLE)
                      
                      glPushMatrix
                      
                      IF tFlags.RotateY THEN
                        glRotateF(AziX!, 0, .001, 0)
                        IF AziY! THEN glRotateF(AziY!, .001, 0, 0)
                      END IF
                      IF tFlags.RotateX THEN
                        glRotateF(AziY!, .001, 0, 0)
                        IF AziX! THEN glRotateF(AziX!, 0, .001, 0)
                      END IF
                      
                      FOR I = 0 TO TileHigh
                      
                        glBegin(%GL_LINE_STRIP)
                      
                        FOR J = 0 TO TileWide
                            glColor3Ub(tPal(I, J).R, tPal(I, J).G, tPal(I, J).B)
                            glVertex3F(tMap(I, J).X, tMap(I, J).Y, tMap(I, J).Elv)
                        NEXT J
                        glEnd
                      NEXT I
                      glPopMatrix
                      END SUB
                      
                      '-----------------------------------------------------------------------------
                      '-----------------------------------------------------------------------------
                      
                      SUB OglQuads(BYVAL TileHigh AS LONG, BYVAL TileWide AS LONG, _
                                   tMap() AS Samp_STRUCT, tPal() AS Color_STRUCT, _
                                   BYVAL AziX AS SINGLE, BYVAL AziY AS SINGLE)
                      
                      glPushMatrix
                      
                      IF tFlags.RotateY THEN
                        glRotateF(AziX!, 0, .001, 0)
                        IF AziY! THEN glRotateF(AziY!, .001, 0, 0)
                      END IF
                      IF tFlags.RotateX THEN
                        glRotateF(AziY!, .001, 0, 0)
                        IF AziX! THEN glRotateF(AziX!, 0, .001, 0)
                      END IF
                      
                      FOR I = 1 TO TileHigh
                        glBegin(%GL_QUADS)
                        FOR J = 1 TO TileWide
                            glColor3Ub(tPal(I - 1, J - 1).R, tPal(I - 1, J - 1).G, tPal(I - 1, J - 1).B)
                            glVertex3F(tMap(I - 1, J - 1).X, tMap(I - 1, J - 1).Y, tMap(I - 1, J - 1).Elv)
                      
                            glColor3Ub(tPal(I - 1, J).R, tPal(I - 1, J).G, tPal(I - 1, J).B)
                            glVertex3F(tMap(I - 1, J).X, tMap(I - 1, J).Y, tMap(I - 1, J).Elv)
                      
                            glColor3Ub(tPal(I, J).R, tPal(I, J).G, tPal(I, J).B)
                            glVertex3F(tMap(I, J).X, tMap(I, J).Y, tMap(I, J).Elv)
                      
                            glColor3Ub(tPal(I, J - 1).R, tPal(I, J - 1).G, tPal(I, J - 1).B)
                            glVertex3F(tMap(I, J - 1).X, tMap(I, J - 1).Y, tMap(I, J - 1).Elv)
                        NEXT J
                        glEnd
                      NEXT I
                      glPopMatrix
                      END SUB
                      
                      '-------------------------------------------------------------
                      '-------------------------------------------------------------
                      
                      SUB Example(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD)
                      
                      LOCAL ClearClr AS DWORD
                      
                      ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                 %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                      
                      GRAPHIC ATTACH Hndl, %GFX_WIN
                      GRAPHIC CLEAR
                      GRAPHIC PRINT "The following triangle has the coordinates:"
                      GRAPHIC SET POS (0, 8)
                      GRAPHIC PRINT "-10, -15, 0"
                      GRAPHIC SET POS (0, 16)
                      GRAPHIC PRINT "10, -15, 0"
                      GRAPHIC SET POS (0, 24)
                      GRAPHIC PRINT "0, -15, 0"
                      GRAPHIC SET POS (0, 32)
                      GRAPHIC PRINT "As you can see, nothing is shown"
                      GRAPHIC DETACH
                      SLEEP 3000
                      
                      glColor3Ub(255, 255, 0)
                      glPushMatrix
                      glRotateF(-90, 0, 1, 0)
                      glBegin(%GL_TRIANGLES)
                        glVertex3F(-10, -15, 0)
                        glVertex3F(10, -15, 0)
                        glVertex3F(0, -15, 0)
                      glEnd
                      Swapbuffers(GfxDc)
                      glPopMatrix
                      glClear(ClearClr)
                      
                      SLEEP 3000
                      GRAPHIC ATTACH Hndl, %GFX_WIN
                      GRAPHIC CLEAR
                      GRAPHIC PRINT "However; when we add a Z value"
                      GRAPHIC SET POS (0, 8)
                      GRAPHIC PRINT "to the 3rd coordinate and then"
                      GRAPHIC SET POS (0, 16)
                      GRAPHIC PRINT "rotate -90 degrees around the X axis"
                      GRAPHIC SET POS (0, 24)
                      GRAPHIC PRINT "we get this:"
                      GRAPHIC DETACH
                      SLEEP 3000
                      
                      glColor3Ub(255, 255, 0)
                      glPushMatrix
                      glRotateF(-90, .001, 0, 0)
                      glBegin(%GL_TRIANGLES)
                        glVertex3F(-10, -15, 0)
                        glVertex3F(10, -15, 0)
                        glVertex3F(0, -15, 15)
                      glEnd
                      Swapbuffers(GfxDc)
                      glPopMatrix
                      glClear(ClearClr)
                      
                      END SUB
                      Last edited by Walt Decker; 12 Jul 2010, 09:38 AM.
                      Walt Decker

                      Comment


                      • #12
                        A Little Light Anyone?

                        I wrote the following example to help me understand how OpenGL treats light. I found that the lighting parameters seem to over-write one another, that the 4th argument of the specular light parameter modifies the highlight diffusion, that the shininess factor gets more intense as it reaches zero and is immediately intense when it exceeds 128.

                        This does not explore all the lighting factors, but it's a start. Hopefully it will help you understand lighting in OpenGL.

                        The code is fairly long, but most of it is menu callback functions. These priovide the ability to change each of the values of the lighting parameters.

                        Code:
                        '=======================================================================
                        '                            OPENGL FUNCTIONS USED
                        '=======================================================================
                        ' glViewport()
                        ' glMatrixMode()
                        ' glLoadIdentity
                        ' glOrtho()
                        ' glMatrixMode()
                        ' glclear()
                        ' glPushMatrix
                        ' glColor3Ub()
                        ' glBegin()
                        ' glEnd
                        ' glVertex3F()
                        ' glPopMatrix
                        ' glFlush
                        ' glEnable()
                        ' glLightFV()
                        ' glColorMaterial()
                        ' glMaterialFV()
                        ' glMaterialI()
                        '=========================================================================
                        '                            WINDOWS FUNCTIONS USED
                        '=========================================================================
                        ' GetDc
                        ' ReleaseDc
                        ' ChoosePixelFormat
                        ' SetPixelFormat
                        ' wglCreateContext
                        ' wglMakeCurrent
                        ' wglDeleteContext
                        '=========================================================================
                        
                        #COMPILE EXE
                        
                        DEFLNG A - Z
                        
                        #INCLUDE "WIN32API.INC"
                        #INCLUDE "pbforms.inc"
                        #INCLUDE "gl.inc"
                        #INCLUDE "glu.inc"
                        
                        TYPE RGB_STRUCT
                          R AS BYTE
                          G AS BYTE
                          B AS BYTE
                        END TYPE
                        
                        TYPE RGBA_STRUCT
                          R AS SINGLE
                          G AS SINGLE
                          B AS SINGLE
                          A AS SINGLE
                        END TYPE
                        
                        TYPE WinRect_STRUCT
                          Ulx AS LONG
                          Uly AS LONG
                          Brx AS LONG
                          Bry AS LONG
                        END TYPE
                        
                        TYPE SpecRef_STRUCT
                          SpecIncRed            AS BIT * 1 IN WORD
                          SpecIncGreen          AS BIT * 1
                          SpecIncBlue           AS BIT * 1
                          SpecDecRed            AS BIT * 1
                          SpecDecGreen          AS BIT * 1
                          SpecDecBlue           AS BIT * 1
                          SpecDefault           AS BIT * 1
                          SpecHiliteInc         AS BIT * 1
                          SpecHiliteDec         AS BIT * 1
                          SpecHiliteDefault     AS BIT * 1
                        END TYPE
                        
                        TYPE Specular_STRUCT
                          Posn          AS BIT * 1 IN WORD
                          SDefInc       AS BIT * 1
                          SDefDec       AS BIT * 1
                          SDefDefault   AS BIT * 1
                          MRefIncRed    AS BIT * 1
                          MRefIncGreen  AS BIT * 1
                          MRefIncBlue   AS BIT * 1
                          MRefDecRed    AS BIT * 1
                          MRefDecGreen  AS BIT * 1
                          MRefDecBlue   AS BIT * 1
                          MRefDefault   AS BIT * 1
                        END TYPE
                        
                        TYPE Ambient_STRUCT
                          AIncRed    AS BIT * 1 IN BYTE
                          AIncBlue   AS BIT * 1
                          AIncGreen  AS BIT * 1
                          ADecRed    AS BIT * 1
                          ADecBlue   AS BIT * 1
                          ADecGreen  AS BIT * 1
                          ADefault   AS BIT * 1
                        END TYPE
                        
                        TYPE Material_STRUCT
                          MIncRed    AS BIT * 1 IN BYTE
                          MIncBlue   AS BIT * 1
                          MIncGreen  AS BIT * 1
                          MDecRed    AS BIT * 1
                          MDecBlue   AS BIT * 1
                          MDecGreen  AS BIT * 1
                          MDefault   AS BIT * 1
                        END TYPE
                        
                        TYPE Rotate_STRUCT
                          RotateX   AS BIT * 1 IN BYTE
                          RotateY   AS BIT * 1
                          RotateZ   AS BIT * 1
                          Track     AS BIT * 1
                        END TYPE
                        
                        TYPE OglFlag_STRUCT
                          EndProg     AS BIT * 1 IN BYTE
                          Lite        AS BIT * 3
                          Rotate_STRUCT
                          Ambient_STRUCT
                          Material_STRUCT
                          Specular_STRUCT
                          SpecRef_STRUCT
                        END TYPE
                        
                        TYPE Single2_STRUCT
                          Mx      AS SINGLE
                          My      AS SINGLE
                        END TYPE
                        
                        TYPE Mouse_Btn_STRUCT
                          LbDown  AS BIT * 1 IN BYTE
                          LbUp    AS BIT * 1
                          RbDown  AS BIT * 1
                          RbUp    AS BIT * 1
                        END TYPE
                        
                        TYPE Mouse_STRUCT
                          Single2_STRUCT
                          Mouse_Btn_STRUCT
                        END TYPE
                        
                        %GFX_WIN     =    5
                        %BTN_END     =    6
                        %BTN_OGL     =    7
                        %LBL_STATUS  =    8
                        
                        %MNU_ROTATEX                     = 10
                        %MNU_ROTATEY                     = 11
                        %MNU_ROTATEZ                     = 12
                        %MNU_TRACK                       = 13
                        %MNU_LITE_INC_RED                = 14
                        %MNU_LITE_INC_GREEN              = 15
                        %MNU_LITE_INC_BLUE               = 16
                        %MNU_LITE_DEC_RED                = 17
                        %MNU_LITE_DEC_GREEN              = 18
                        %MNU_LITE_DEC_BLUE               = 19
                        %MNU_LITE_DEFAULT                = 20
                        %MNU_MAT_INC_RED                 = 21
                        %MNU_MAT_INC_GREEN               = 22
                        %MNU_MAT_INC_BLUE                = 23
                        %MNU_MAT_DEC_RED                 = 24
                        %MNU_MAT_DEC_GREEN               = 25
                        %MNU_MAT_DEC_BLUE                = 26
                        %MNU_MAT_DEFAULT                 = 27
                        
                        %MNU_AMBIENT_ONLY               = 30
                        %MNU_SPEC_ORIGIN                = 31
                        %MNU_DEF_INCREASE               = 32
                        %MNU_DEF_DECREASE               = 33
                        %MNU_DEF_DEFAULT                = 34
                        %MNU_MAT_REF_INC_RED            = 35
                        %MNU_MAT_REF_INC_GREEN          = 36
                        %MNU_MAT_REF_INC_BLUE           = 37
                        %MNU_MAT_REF_DEC_RED            = 38
                        %MNU_MAT_REF_DEC_GREEN          = 39
                        %MNU_MAT_REF_DEC_BLUE           = 40
                        %MNU_MAT_REF_DEFAULT            = 41
                        
                        %MNU_SPEC_INC_RED               = 50
                        %MNU_SPEC_INC_GREEN             = 51
                        %MNU_SPEC_INC_BLUE              = 52
                        %MNU_SPEC_DEC_RED               = 53
                        %MNU_SPEC_DEC_GREEN             = 54
                        %MNU_SPEC_DEC_BLUE              = 55
                        %MNU_SPEC_DEFAULT               = 56
                        %MNU_SPEC_HILITE_INC            = 57
                        %MNU_SPEC_HILITE_DEC            = 58
                        %MNU_SPEC_HILITE_DEFAULT        = 59
                        
                        %OGL_ERROR   = %WM_USER + 500
                        %TEST        = 0
                        
                        GLOBAL MnuHndl AS DWORD
                        
                        GLOBAL tFlags AS OglFlag_STRUCT
                        GLOBAL tMouse AS Mouse_STRUCT
                        
                        DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR, BYVAL Flag AS BYTE)
                        DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
                        DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                                    GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                        
                        DECLARE SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                         BYVAL OrthoRange AS LONG)
                        
                        DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                                BYVAL GfxHndl AS DWORD)
                        
                        DECLARE SUB FindPolyNormal(Vector3() AS SINGLE, PNormal() AS SINGLE)
                        DECLARE SUB FindUnitNormal(NormalV() AS SINGLE)
                        
                        DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                                    tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                        
                        DECLARE FUNCTION PBMAIN() AS LONG
                        
                        DECLARE CALLBACK FUNCTION Main_CB()
                        DECLARE CALLBACK FUNCTION AmbMnu_CB()
                        DECLARE CALLBACK FUNCTION RotMnu_CB()
                        DECLARE CALLBACK FUNCTION MatMnu_CB()
                        DECLARE CALLBACK FUNCTION SpecMnu_CB()
                        DECLARE CALLBACK FUNCTION SpecRefMnu_CB()
                        
                        '----------------------------------------------------------------------------
                        '----------------------------------------------------------------------------
                        
                        CALLBACK FUNCTION SpecRefMnu_CB()
                        
                        IF CBMSG = %WM_COMMAND THEN
                          IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                        
                            SELECT CASE CBCTL
                              CASE %MNU_SPEC_INC_RED
                                IF tFlags.SpecIncRed THEN
                                  tFlags.SpecIncRed = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                ELSE
                                  tFlags.SpecIncRed = 1
                                  tFlags.SpecDecRed = 0
                                  tFlags.SpecDefault = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                END IF
                        
                              CASE %MNU_SPEC_INC_GREEN
                                IF tFlags.SpecIncGreen THEN
                                  tFlags.SpecIncGreen = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                ELSE
                                  tFlags.SpecIncGreen = 1
                                  tFlags.SpecDecGreen = 0
                                  tFlags.SpecDefault = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                END IF
                        
                              CASE %MNU_SPEC_INC_BLUE
                                IF tFlags.SpecIncBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecIncBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecIncBlue = 1
                                  tFlags.SpecDecBlue = 0
                                  tFlags.SpecDefault = 0
                                END IF
                        
                              CASE %MNU_SPEC_DEC_RED
                                IF tFlags.SpecDecRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecDecRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecDecRed = 1
                                  tFlags.SpecIncRed = 0
                                  tFlags.SpecDefault = 0
                                END IF
                        
                              CASE %MNU_SPEC_DEC_GREEN
                                IF tFlags.SpecDecGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecDecGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecDecGreen = 1
                                  tFlags.SpecIncGreen = 0
                                  tFlags.SpecDefault = 0
                                END IF
                        
                              CASE %MNU_SPEC_DEC_BLUE
                                IF tFlags.SpecDecBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecDecBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecDecBlue = 1
                                  tFlags.SpecIncBlue = 0
                                  tFlags.SpecDefault = 0
                                END IF
                        
                              CASE %MNU_SPEC_DEFAULT
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEFAULT, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                tFlags.SpecDefault = 1
                                tFlags.SpecIncRed = 0
                                tFlags.SpecIncGreen = 0
                                tFlags.SpecIncBlue = 0
                                tFlags.SpecDecRed = 0
                                tFlags.SpecDecGreen = 0
                                tFlags.SpecDecBlue = 0
                        
                              CASE %MNU_SPEC_HILITE_INC
                                IF tFlags.SpecHiliteInc THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_INC, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecHiliteInc = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_INC, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEC, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecHiliteInc = 1
                                  tFlags.SpecHiliteDec = 0
                                  tFlags.SpecHiliteDefault = 0
                                END IF
                        
                              CASE %MNU_SPEC_HILITE_DEC
                                IF tFlags.SpecHiliteDec THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEC, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecHiliteDec = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEC, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_INC, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.SpecHiliteInc = 0
                                  tFlags.SpecHiliteDec = 1
                                  tFlags.SpecHiliteDefault = 0
                                END IF
                        
                              CASE %MNU_SPEC_HILITE_DEFAULT
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEC, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_INC, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_SPEC_HILITE_DEFAULT, %MF_CHECKED OR %MF_ENABLED
                                  tFlags.SpecHiliteInc = 0
                                  tFlags.SpecHiliteDec = 0
                                  tFlags.SpecHiliteDefault = 1
                            END SELECT
                          END IF
                        END IF
                        '
                        END FUNCTION
                        
                        '----------------------------------------------------------------------------
                        '----------------------------------------------------------------------------
                        
                        CALLBACK FUNCTION SpecMnu_CB()
                        
                        IF CBMSG = %WM_COMMAND THEN
                          IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                        
                            SELECT CASE CBCTL
                              CASE %MNU_AMBIENT_ONLY
                                IF tFlags.Lite THEN
                                  tFlags.Lite = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_AMBIENT_ONLY, %MF_CHECKED OR %MF_ENABLED
                                END IF
                        
                              CASE %MNU_SPEC_ORIGIN
                                IF tFlags.Lite = 0 THEN
                                  tFlags.Lite = 1
                                  MENU SET STATE MnuHndl, BYCMD %MNU_AMBIENT_ONLY, %MF_UNCHECKED OR %MF_ENABLED
                                END IF
                                tFlags.Posn = 1
                        
                              CASE %MNU_DEF_INCREASE
                                MSGBOX "def inc"
                                IF tFlags.SDefInc THEN
                                  tFlags.SDefInc = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_INCREASE, %MF_UNCHECKED OR %MF_ENABLED
                                ELSE
                                  tFlags.SDefInc = 1
                                  tFlags.SDefDec = 0
                                  tFlags.SDefDefault = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_INCREASE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DECREASE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                END IF
                        
                              CASE %MNU_DEF_DECREASE
                                IF tFlags.SDefDec THEN
                                  tFlags.SDefDec = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DECREASE, %MF_UNCHECKED OR %MF_ENABLED
                                ELSE
                                  tFlags.SDefDec = 1
                                  tFlags.SDefInc = 0
                                  tFlags.SDefDefault = 0
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DECREASE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_INCREASE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                END IF
                              CASE %MNU_DEF_DEFAULT
                                MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DEFAULT, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_DEF_DECREASE, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_DEF_INCREASE, %MF_UNCHECKED OR %MF_ENABLED
                                tFlags.SDefDefault = 1
                                tFlags.SDefInc = 0
                                tFlags.SDefDec = 0
                        
                              CASE %MNU_MAT_REF_INC_RED
                                IF tFlags.MRefIncRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefIncRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefIncRed = 1
                                  tFlags.MRefDecRed = 0
                                  tFlags.MRefDefault = 0
                                END IF
                        
                              CASE %MNU_MAT_REF_INC_GREEN
                                IF tFlags.MRefIncGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefIncGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefIncGreen = 1
                                  tFlags.MRefDecGreen = 0
                                  tFlags.MRefDefault = 0
                                END IF
                        
                              CASE %MNU_MAT_REF_INC_BLUE
                                IF tFlags.MRefIncBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefIncBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefIncBlue = 1
                                  tFlags.MRefDecBlue = 0
                                  tFlags.MRefDefault = 0
                                END IF
                        
                              CASE %MNU_MAT_REF_DEC_RED
                                IF tFlags.MRefDecRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDecRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDecRed = 1
                                  tFlags.MRefIncRed = 0
                                  tFlags.MRefDefault = 0
                                END IF
                        
                              CASE %MNU_MAT_REF_DEC_GREEN
                                IF tFlags.MRefDecGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDecGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDecGreen = 1
                                  tFlags.MRefIncGreen = 0
                                  tFlags.MRefDefault = 0
                                END IF
                        
                              CASE %MNU_MAT_REF_DEC_BLUE
                                IF tFlags.MRefDecBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDecBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDecBlue = 1
                                  tFlags.MRefIncBlue = 0
                                  tFlags.MRefDefault = 0
                                END IF
                        
                              CASE %MNU_MAT_REF_DEFAULT
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEFAULT, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_REF_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MRefDefault = 1
                                  tFlags.MRefIncRed = 0
                                  tFlags.MRefIncGreen = 0
                                  tFlags.MRefIncBlue = 0
                                  tFlags.MRefDecRed = 0
                                  tFlags.MRefDecGreen = 0
                                  tFlags.MRefDecBlue = 0
                        
                            END SELECT
                          END IF
                        END IF
                        '
                        END FUNCTION
                        
                        '----------------------------------------------------------------
                        '----------------------------------------------------------------
                        CALLBACK FUNCTION MatMnu_CB()
                        
                        IF CBMSG = %WM_COMMAND THEN
                          IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                        
                            SELECT CASE CBCTL
                              CASE %MNU_MAT_INC_RED
                                IF tFlags.MIncRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncRed = 1
                                  tFlags.MDefault = 0
                                  tFlags.MDecRed = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_MAT_INC_GREEN
                                IF tFlags.MIncGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncGreen = 1
                                  tFlags.MDefault = 0
                                  tFlags.MDecGreen = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_MAT_INC_BLUE
                                IF tFlags.MIncBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncBlue = 1
                                  tFlags.MDefault = 0
                                  tFlags.MDecBlue = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_MAT_DEC_RED
                                IF tFlags.MDecRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MIncRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MDecRed = 1
                                  tFlags.MDefault = 0
                                  tFlags.MIncRed = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_MAT_DEC_GREEN
                                IF tFlags.MDecGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MDecGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MDecGreen = 1
                                  tFlags.MDefault = 0
                                  tFlags.MIncGreen = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_MAT_DEC_BLUE
                                IF tFlags.MDecBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MDecBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.MDecBlue = 1
                                  tFlags.MDefault = 0
                                  tFlags.MIncBlue = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_MAT_DEFAULT
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEFAULT, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_MAT_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                tFlags.MDefault = 1
                                tFlags.MIncRed = 0
                                tFlags.MIncGreen = 0
                                tFlags.MIncBlue = 0
                                tFlags.MDecRed = 0
                                tFlags.MDecGreen = 0
                                tFlags.MDecBlue = 0
                                FUNCTION = 1
                        
                            END SELECT
                          END IF
                        END IF
                        '
                        END FUNCTION
                        
                        '-----------------------------------------------------------------
                        '-----------------------------------------------------------------
                        
                        CALLBACK FUNCTION RotMnu_CB()
                        
                        IF CBMSG = %WM_COMMAND THEN
                          IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                        
                            SELECT CASE CBCTL
                              CASE %MNU_ROTATEX
                                IF tFlags.RotateX THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.RotateX = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.RotateX = 1
                                  tFlags.RotateY = 0
                                  tFlags.RotateZ = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_ROTATEY
                                IF tFlags.RotateY THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.RotateY = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.RotateX = 0
                                  tFlags.RotateY = 1
                                  tFlags.RotateZ = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_ROTATEZ
                                IF tFlags.RotateZ THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.RotateZ = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEZ, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEX, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_ROTATEY, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.RotateX = 0
                                  tFlags.RotateY = 0
                                  tFlags.RotateZ = 1
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_TRACK
                                IF tFlags.Track THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_TRACK, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.Track = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_TRACK, %MF_CHECKED OR %MF_ENABLED
                                  tFlags.Track = 1
                                END IF
                                FUNCTION = 1
                            END SELECT
                          END IF
                        END IF
                        END FUNCTION
                        
                        '-----------------------------------------------------------
                        '-----------------------------------------------------------
                        
                        CALLBACK FUNCTION AmbMnu_CB()
                        
                        IF CBMSG = %WM_COMMAND THEN
                          IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                        
                            SELECT CASE CBCTL
                              CASE %MNU_LITE_INC_RED
                                IF tFlags.AIncRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncRed = 1
                                  tFlags.ADefault = 0
                                  tFlags.ADecRed = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_LITE_INC_GREEN
                                IF tFlags.AIncGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncGreen = 1
                                  tFlags.ADefault = 0
                                  tFlags.ADecGreen = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_LITE_INC_BLUE
                                IF tFlags.AIncBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncBlue = 1
                                  tFlags.ADefault = 0
                                  tFlags.ADecBlue = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_LITE_DEC_RED
                                IF tFlags.ADecRed THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.AIncRed = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_RED, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.ADecRed = 1
                                  tFlags.ADefault = 0
                                  tFlags.AIncRed = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_LITE_DEC_GREEN
                                IF tFlags.ADecGreen THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.ADecGreen = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_GREEN, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.ADecGreen = 1
                                  tFlags.ADefault = 0
                                  tFlags.AIncGreen = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_LITE_DEC_BLUE
                                IF tFlags.ADecBlue THEN
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.ADecBlue = 0
                                ELSE
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_BLUE, %MF_CHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_UNCHECKED OR %MF_ENABLED
                                  MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                  tFlags.ADecBlue = 1
                                  tFlags.ADefault = 0
                                  tFlags.AIncBlue = 0
                                END IF
                                FUNCTION = 1
                        
                              CASE %MNU_LITE_DEFAULT
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEFAULT, %MF_CHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_INC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_RED, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_GREEN, %MF_UNCHECKED OR %MF_ENABLED
                                MENU SET STATE MnuHndl, BYCMD %MNU_LITE_DEC_BLUE, %MF_UNCHECKED OR %MF_ENABLED
                                tFlags.ADefault = 1
                                tFlags.AIncRed = 0
                                tFlags.AIncGreen = 0
                                tFlags.AIncBlue = 0
                                tFlags.ADecRed = 0
                                tFlags.ADecGreen = 0
                                tFlags.ADecBlue = 0
                                FUNCTION = 1
                        
                            END SELECT
                          END IF
                        END IF
                        '
                        END FUNCTION
                        
                        '-----------------------------------------------------------------
                        '-----------------------------------------------------------------
                        
                        FUNCTION PBMAIN()
                        
                        LOCAL hDlg AS DWORD
                        LOCAL hPopUp1 AS DWORD
                        LOCAL hPopUp2 AS DWORD
                        LOCAL hPopUp3 AS DWORD
                        LOCAL hPopUp4 AS DWORD
                        
                        DIALOG NEW PIXELS, 0, "Exploring Ogl - A Little Light", , , 420, 290, _
                                          %WS_POPUP OR %WS_BORDER _
                                          OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                          %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                          %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                          %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                        
                        CONTROL ADD LABEL,   hDlg, %LBL_STATUS, "", 300, 5, 120, 245, %WS_CHILD OR _
                            %WS_VISIBLE OR %WS_BORDER OR %SS_LEFT, %WS_EX_LEFT OR %WS_EX_LTRREADING
                        
                        CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 225, 85, 20, %WS_CHILD _
                          OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                          %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                          %WS_EX_LTRREADING
                        
                        CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl", 120, 225, 75, 20, _
                          %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                          OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                          %WS_EX_LTRREADING
                        
                        DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
                        CONTROL SET COLOR    hDlg, %LBL_STATUS, %BLUE, -1
                        
                        hFont1 = PBFormsMakeFont("Arial", 8, 400, %FALSE, %FALSE, %FALSE, _
                                                 %ANSI_CHARSET)
                        
                        CONTROL SEND hDlg, %LBL_STATUS, %WM_SETFONT, hFont1, 0
                        
                          MENU NEW BAR TO MnuHndl
                          MENU NEW POPUP TO hPopUp1
                          MENU ADD POPUP, MnuHndl, "Rotate", hPopUp1, %MF_ENABLED
                            MENU ADD STRING, hPopUp1, "X Axis", %MNU_ROTATEX, %MF_ENABLED, CALL RotMnu_CB()
                            MENU ADD STRING, hPopUp1, "Y Axis", %MNU_ROTATEY, %MF_ENABLED, CALL RotMnu_CB()
                            MENU ADD STRING, hPopUp1, "Z Axis", %MNU_ROTATEZ, %MF_ENABLED, CALL RotMnu_CB()
                            MENU ADD STRING, hPopUp1, "Track",  %MNU_TRACK, %MF_ENABLED OR %MF_CHECKED, _
                                                                CALL RotMnu_CB()
                          MENU NEW POPUP TO hPopUp1
                          MENU ADD POPUP, MnuHndl, "Ambient", hPopUp1, %MF_ENABLED
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Increase", hPopUp2, %MF_ENABLED
                              MENU ADD STRING, hPopUp2, "Red", %MNU_LITE_INC_RED, %MF_ENABLED, _
                                                               CALL AmbMnu_CB()
                              MENU ADD STRING, hPopUp2, "Green", %MNU_LITE_INC_GREEN, %MF_ENABLED, _
                                                               CALL AmbMnu_CB()
                              MENU ADD STRING, hPopUp2, "Blue", %MNU_LITE_INC_BLUE, %MF_ENABLED, _
                                                               CALL AmbMnu_CB()
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Decrease", hPopUp2, %MF_ENABLED
                              MENU ADD STRING, hPopUp2, "Red", %MNU_LITE_DEC_RED, %MF_ENABLED, _
                                                               CALL AmbMnu_CB()
                              MENU ADD STRING, hPopUp2, "Green", %MNU_LITE_DEC_GREEN, %MF_ENABLED, _
                                                               CALL AmbMnu_CB()
                              MENU ADD STRING, hPopUp2, "Blue", %MNU_LITE_DEC_BLUE, %MF_ENABLED, _
                                                               CALL AmbMnu_CB()
                            MENU ADD STRING, hPopUp1, "Default", %MNU_LITE_DEFAULT, %MF_ENABLED OR %MF_CHECKED, _
                                                               CALL AmbMnu_CB()
                          MENU NEW POPUP TO hPopUp1
                          MENU ADD POPUP, MnuHndl, "Diffusion", hPopUp1, %MF_ENABLED
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Increase", hPopUp2, %MF_ENABLED
                              MENU ADD STRING, hPopUp2, "Red", %MNU_MAT_INC_RED, %MF_ENABLED, _
                                                               CALL MatMnu_CB()
                              MENU ADD STRING, hPopUp2, "Green", %MNU_MAT_INC_GREEN, %MF_ENABLED, _
                                                               CALL MatMnu_CB()
                              MENU ADD STRING, hPopUp2, "Blue", %MNU_MAT_INC_BLUE, %MF_ENABLED, _
                                                               CALL MatMnu_CB()
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Decrease", hPopUp2, %MF_ENABLED
                              MENU ADD STRING, hPopUp2, "Red", %MNU_MAT_DEC_RED, %MF_ENABLED, _
                                                               CALL MatMnu_CB()
                              MENU ADD STRING, hPopUp2, "Green", %MNU_MAT_DEC_GREEN, %MF_ENABLED, _
                                                               CALL MatMnu_CB()
                              MENU ADD STRING, hPopUp2, "Blue", %MNU_MAT_DEC_BLUE, %MF_ENABLED, _
                                                               CALL MatMnu_CB()
                            MENU ADD STRING, hPopUp1, "Default", %MNU_MAT_DEFAULT, %MF_ENABLED OR %MF_CHECKED, _
                                                               CALL MatMnu_CB()
                          MENU NEW POPUP TO hPopUp1
                          MENU ADD POPUP, MnuHndl, "Specular", hPopUp1, %MF_ENABLED
                            MENU ADD STRING, hPopUp1, "Ambient Only", %MNU_AMBIENT_ONLY, %MF_ENABLED OR %MF_CHECKED, _
                                                               CALL SpecMnu_CB()
                            MENU ADD STRING, hPopUp1, "Light Origin", %MNU_SPEC_ORIGIN, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Origin Diffusion Factor", hPopUp2, %MF_ENABLED
                              MENU ADD STRING, hPopUp2, "Increase", %MNU_DEF_INCREASE, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                              MENU ADD STRING, hPopUp2, "Decrease", %MNU_DEF_DECREASE, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                              MENU ADD STRING, hPopUp2, "Default", %MNU_DEF_DEFAULT, %MF_ENABLED OR %MF_CHECKED, _
                                                               CALL SpecMnu_CB()
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Material Reflectance", hPopUp2, %MF_ENABLED
                              MENU NEW POPUP TO hPopUp3
                              MENU ADD POPUP, hPopUp2, "Increase", hPopUp3, %MF_ENABLED
                                MENU ADD STRING, hPopUp3, "Red", %MNU_MAT_REF_INC_RED, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                                MENU ADD STRING, hPopUp3, "Green", %MNU_MAT_REF_INC_GREEN, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                                MENU ADD STRING, hPopUp3, "Blue", %MNU_MAT_REF_INC_BLUE, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                              MENU NEW POPUP TO hPopUp3
                              MENU ADD POPUP, hPopUp2, "Decrease", hPopUp3, %MF_ENABLED
                                MENU ADD STRING, hPopUp3, "Red", %MNU_MAT_REF_DEC_RED, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                                MENU ADD STRING, hPopUp3, "Green", %MNU_MAT_REF_DEC_GREEN, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                                MENU ADD STRING, hPopUp3, "Blue", %MNU_MAT_REF_DEC_BLUE, %MF_ENABLED, _
                                                               CALL SpecMnu_CB()
                              MENU ADD STRING, hPopUp2, "Default", %MNU_MAT_REF_DEFAULT, %MF_ENABLED OR %MF_CHECKED, _
                                                               CALL SpecMnu_CB()
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "Specular Reflectance", hPopUp2, %MF_ENABLED
                              MENU NEW POPUP TO hPopUp3
                              MENU ADD POPUP, hPopUp2, "Increase", hPopUp3, %MF_ENABLED
                                MENU ADD STRING, hPopUp3, "Red", %MNU_SPEC_INC_RED, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                                MENU ADD STRING, hPopUp3, "Green", %MNU_SPEC_INC_GREEN, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                                MENU ADD STRING, hPopUp3, "Blue", %MNU_SPEC_INC_BLUE, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                              MENU NEW POPUP TO hPopUp3
                              MENU ADD POPUP, hPopUp2, "Decrease", hPopUp3, %MF_ENABLED
                                MENU ADD STRING, hPopUp3, "Red", %MNU_SPEC_DEC_RED, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                                MENU ADD STRING, hPopUp3, "Green", %MNU_SPEC_DEC_GREEN, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                                MENU ADD STRING, hPopUp3, "Blue", %MNU_SPEC_DEC_BLUE, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                              MENU ADD STRING, hPopUp2, "Default", %MNU_SPEC_DEFAULT, %MF_ENABLED OR %MF_CHECKED, _
                                                                CALL SpecRefMnu_CB()
                            MENU NEW POPUP TO hPopUp2
                            MENU ADD POPUP, hPopUp1, "HighLite Exponent", hPopUp2, %MF_ENABLED
                              MENU ADD STRING, hPopUp2, "Increase", %MNU_SPEC_HILITE_INC, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                              MENU ADD STRING, hPopUp2, "Decrease", %MNU_SPEC_HILITE_DEC, %MF_ENABLED, _
                                                                CALL SpecRefMnu_CB()
                              MENU ADD STRING, hPopUp2, "Default", %MNU_SPEC_HILITE_DEFAULT, %MF_ENABLED OR %MF_CHECKED, _
                                                                CALL SpecRefMnu_CB()
                        
                        MENU ATTACH MnuHndl, hDlg
                        
                        tFlags.Track = 1
                        tFlags.ADefault = 1
                        tFlags.MDefault = 1
                        tFlags.SpecDefault = 1
                        tFlags.SpecHiliteDefault = 1
                        tFlags.SDefDefault = 1
                        tFlags.MRefDefault = 1
                        tFlags.Lite = 0
                        
                        DIALOG SHOW MODAL hDlg, CALL Main_CB
                        
                        DeleteObject hFont1
                        END FUNCTION
                        
                        '------------------------------------------------------------
                        '------------------------------------------------------------
                        
                        CALLBACK FUNCTION Main_CB()
                        
                        LOCAL lParam AS LONG
                        LOCAL wParam AS LONG
                        
                        SELECT CASE AS LONG CBMSG
                        
                          wParam = CBWPARAM
                          CASE %WM_INITDIALOG
                            Inst = GetWindowLong(CBHNDL, %GWL_HINSTANCE)
                            Styl = %CS_HREDRAW OR %CS_VREDRAW OR %CS_OWNDC OR %CS_GLOBALCLASS
                        
                            CALL RegWindow("OglCtl" + $NUL, Styl, CODEPTR(FnGfx_Ctl_CB), Inst, %GRAY_BRUSH, 0)
                        
                            Styl = %WS_VISIBLE OR %WS_TABSTOP OR %WS_CHILD
                        
                            CONTROL ADD "OglCtl", CBHNDL, %GFX_WIN, "", 5, 25, 290, 190, Styl, %WS_EX_CLIENTEDGE
                        
                          CASE %WM_COMMAND
                            wParam = CBCTLMSG
                            SELECT CASE AS LONG wParam
                              CASE %BN_CLICKED, %STN_CLICKED, 1
                                SELECT CASE AS LONG CBCTL
                                  CASE %GFX_WIN
                                    EXIT FUNCTION
                        
                                  CASE %BTN_END
                                    tFlags.EndProg = 1
                                    CALL RunOgl(CBHNDL)
                                    DIALOG END CBHNDL
                                    FUNCTION = 1
                                    EXIT FUNCTION
                        
                                  CASE %BTN_OGL
                                    CONTROL DISABLE CBHNDL, %BTN_OGL
                                    CALL RunOgl(CBHNDL)
                                    FUNCTION = 1
                                    EXIT FUNCTION
                        
                                END SELECT
                            END SELECT
                        
                          CASE %WM_DESTROY
                            IF tFlags.EndProg THEN EXIT SELECT
                            tFlags.EndProg = 1
                            CALL RunOgl(CBHNDL)
                        
                          CASE %OGL_ERROR
                            SELECT CASE wParam
                              CASE 1
                                MSGBOX "Could not find matching pixel format: error #" + STR$(wParam)
                              CASE 2
                                MSGBOX "Could not set selected pixel format: error #" + STR$(wParam)
                              CASE 3
                                MSGBOX "Could not create rendering context: error #" + STR$(wParam)
                              CASE 4
                                MSGBOX "Could not make rendering context current.  Defined window may not" _
                                       + " support it: error #" + STR$(wParam)
                            END SELECT
                            DIALOG END CBHNDL
                        END SELECT
                        
                        END FUNCTION
                        
                        '------------------------------------------------------------
                        '------------------------------------------------------------
                        
                        SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR, BYVAL Flag AS BYTE)
                        
                        '==============================================================
                        ' This is the 1st step in setting up windows for OpenGl support
                        ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
                        ' graphics
                        '==============================================================
                        
                        LOCAL FlagParam AS DWORD
                        
                        IF Flag THEN
                          FlagParam = %PFD_DRAW_TO_WINDOW OR PFD_DRAW_TO_BITMAP OR %PFD_SUPPORT_OPENGL _
                                      OR %PFD_DOUBLEBUFFER
                        ELSE
                          FlagParam = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
                        END IF
                        
                        pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
                        pfd.nversion = 1
                        pfd.dwflags = FlagParam
                        pfd.dwlayermask = %PFD_MAIN_PLANE
                        pfd.ipixeltype = %PFD_TYPE_RGBA
                        pfd.ccolorbits = 24
                        pfd.cdepthbits = 24
                        pfd.caccumbits = 0
                        pfd.cstencilbits = 0
                        
                        END SUB
                        
                        '---------------------------------------------------------------
                        '---------------------------------------------------------------
                        
                        SUB RunOgl(BYVAL Hndl AS DWORD)
                        
                        STATIC Wide  AS LONG
                        STATIC High  AS LONG
                        
                        STATIC GfxDC     AS DWORD
                        STATIC OglRc     AS DWORD
                        STATIC GfxHndl   AS DWORD
                        
                        LOCAL ClearClr   AS DWORD
                        
                        LOCAL LiteExponent AS INTEGER
                        
                        LOCAL tPixFmt   AS PIXELFORMATDESCRIPTOR
                        LOCAL tRect     AS WinRect_STRUCT
                        LOCAL tMPos     AS single2_STRUCT
                        LOCAL tColor()  AS RGB_STRUCT
                        LOCAL tPnts()   AS RGBA_STRUCT
                        LOCAL tNormal() AS RGBA_STRUCT
                        
                        LOCAL Ambient()     AS SINGLE
                        LOCAL Diffusion()   AS SINGLE
                        LOCAL MatReflect()  AS SINGLE
                        LOCAL SpecReflect() AS SINGLE
                        LOCAL LightPosn()   AS SINGLE
                        LOCAL Dummy()       AS SINGLE
                        
                        LOCAL X   AS SINGLE
                        LOCAL Y   AS SINGLE
                        LOCAL Z   AS SINGLE
                        LOCAL Azi AS SINGLE
                        
                        LOCAL Txt AS STRING
                        
                        IF ISFALSE(GfxDc) THEN
                          IF tFlags.EndProg THEN EXIT SUB
                          CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                          CALL OglPixFormat(tPixFmt, 0)
                        
                          OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
                        
                          IF OglRc = 0 THEN EXIT SUB
                        
                          CALL SetOglWindow(Wide, High, 100)
                        ELSE
                          IF tFlags.EndProg THEN
                            CloseOpenGL(OglRc, GfxDc, GfxHndl)
                            EXIT SUB
                           END IF
                        END IF
                        
                        IF %TEST THEN
                          GRAPHIC WINDOW "test", 0, 0, 200, 200 TO WinHndl
                          GRAPHIC ATTACH WinHndl, 0
                        END IF
                        
                        DIM Ambient(3)
                        DIM Diffusion(3)
                        DIM MatReflect(3)
                        DIM SpecReflect(3)
                        DIM LightPosn(3)
                        DIM Dummy(3)
                        
                        MAT Ambient()   = CON
                        MAT Diffusion()  = CON
                        MAT MatReflect() = CON
                        MAT SpecReflect() = CON
                        
                        LiteExponent = 128
                        
                        CALL Color_Data(tColor())
                        CALL Obj_Data(tPnts())
                        CALL GetNormals(tPnts(), tNormal())
                        
                        ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                   %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                        
                        IF tFlags.Posn THEN
                          CALL LightPos(tMpos)
                          CALL Zdepth
                          CALL WindowToProjection(tMpos.Mx, tMpos.My, 0)
                          CALL WindowToProjection(0, tMouse.My, 0)
                          LightPosn(0) = tMpos.Mx
                          LightPosn(1) = tMpos.My
                          LightPosn(2) = tMouse.My
                          LightPosn(3) = 1
                          RESET tMouse, tMpos
                          tFlags.Posn = 0
                        END IF
                        
                        DO
                          DIALOG DOEVENTS
                          IF tFlags.EndProg THEN EXIT SUB
                          IF tMouse.RbDown THEN EXIT SUB
                          IF tMouse.LbDown THEN
                        
                            DIALOG DOEVENTS
                            IF tFlags.EndProg THEN EXIT SUB
                            IF tMouse.RbDown THEN EXIT DO
                        
                            IF tFlags.Posn THEN
                              CALL LightPos(tMpos)
                              CALL Zdepth
                              CALL WindowToProjection(tMpos.Mx, tMpos.My, 0)
                              CALL WindowToProjection(0, tMouse.My, 0)
                              LightPosn(0) = tMpos.Mx
                              LightPosn(1) = tMpos.My
                              LightPosn(2) = tMouse.My
                              LightPosn(3) = 1
                              RESET tMouse, tMpos
                              tFlags.Posn = 0
                            END IF
                        
                            IF tFlags.Track THEN
                              IF (tMpos.Mx = tMouse.Mx) AND (tMpos.My = tMouse.My) THEN EXIT IF
                              IF tFlags.Lite = 0 THEN
                                CALL Lite_Properties(Ambient(), Dummy(), Dummy(), Dummy(), 0, 0)
                              ELSE
                                CALL Lite_Properties(Ambient(), Diffusion(), MatReflect(), _
                                                     SpecReflect(),LightPosn(3), LiteExponent)
                              END IF
                            END IF
                        
                            IF (tMpos.Mx <> tMouse.Mx) OR (tMpos.My <> tMouse.My) THEN
                              IF tFlags.RotateX THEN X = X + (tMpos.My - tMouse.My) * 1.25
                              IF tFlags.RotateY THEN Y = Y + tMpos.Mx - tMouse.Mx
                              IF tFlags.RotateZ THEN
                                Z = tMpos.Mx / tMouse.My
                                Azi = Azi + Z
                              END IF
                              tMpos.Mx = tMouse.Mx
                              tMpos.My = tMouse.My
                            END IF
                        
                            Txt$ = ""
                            IF tFlags.Lite = 0 THEN
                              Txt$ = SPACE$(8) + "Ambient:" + $CRLF + _
                              "R: " + FORMAT$(Ambient(0)) + $CRLF + _
                              "G: " + FORMAT$(Ambient(1)) + $CRLF + _
                              "B: " + FORMAT$(Ambient(2))
                            ELSE
                              Txt$ = SPACE$(8) + " Ambient:" + $CRLF + _
                              "R: " + FORMAT$(Ambient(0)) + $CRLF + _
                              "G: " + FORMAT$(Ambient(1)) + $CRLF + _
                              "B: " + FORMAT$(Ambient(2)) + $CRLF + _
                                    SPACE$(5) + "Diffusion:" + $CRLF + _
                              "R: " + FORMAT$(Diffusion(0)) + $CRLF + _
                              "G: " + FORMAT$(Diffusion(1)) + $CRLF + _
                              "B: " + FORMAT$(Diffusion(2)) + $CRLF + _
                                    " Mat Reflectance" + $CRLF + _
                              "R: " + FORMAT$(MatReflect(0)) + $CRLF + _
                              "G: " + FORMAT$(MatReflect(1)) + $CRLF + _
                              "B: " + FORMAT$(MatReflect(2)) + $CRLF + _
                                    " Spec Reflectance" + $CRLF + _
                              "R: " + FORMAT$(SpecReflect(0)) + $CRLF + _
                              "G: " + FORMAT$(SpecReflect(1)) + $CRLF + _
                              "B: " + FORMAT$(SpecReflect(2)) + $CRLF + _
                                    "Posn Diff: " + FORMAT$(LightPosn(3)) + $CRLF + _
                                    "Spec ^:" + FORMAT$(LiteExponent)
                            END IF
                            CONTROL SET TEXT Hndl, %LBL_STATUS, Txt$
                            IF tFlags.Lite = 0 THEN CALL Ambient_Light(Ambient())
                            IF tFlags.Lite = 1 THEN CALL Spec_Light(Ambient(), Diffusion(), _
                                                                    MatReflect(), SpecReflect(), _
                                                                    LightPosn(), LiteExponent)
                            glEnable(%GL_DEPTH_TEST)
                        
                            CALL OglRenderImage(X, Y, Azi, tColor(), tPnts(), tNormal())
                        
                            SwapBuffers(GfxDc)
                            glClear(ClearClr)
                            glFlush
                            glDisable(%GL_LIGHTING)
                            glDisable(%GL_DEPTH_TEST)
                            glDisable(%GL_COLOR_MATERIAL)
                            glFlush
                            glFinish
                          END IF
                          RESET tMouse
                        LOOP
                        
                        END SUB
                        
                        '----------------------------------------------------------------
                        '----------------------------------------------------------------
                        
                        FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                            tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                        
                        '================================================================
                        '  This is the second step for OpenGL support
                        '  ChoosePixelFormat selects a pixel format that matches that
                        '  described in the PIXELFORMATDESCRIPTOR structure.
                        '
                        '  Each step is the setup is quried because not all windows support
                        '  OpenGL rendering
                        '================================================================
                        
                        LOCAL PixFormat AS DWORD
                        LOCAL OglRc     AS DWORD
                        
                        LOCAL T AS LONG
                        
                        PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
                        
                        IF ISFALSE (PixFormat) THEN
                          DIALOG POST Hndl, %OGL_ERROR, 1, 0
                          EXIT FUNCTION
                        END IF
                        
                        t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
                        
                        IF ISFALSE(t) THEN
                          DIALOG POST Hndl, %OGL_ERROR, 2, 0
                          EXIT FUNCTION
                        END IF
                        
                        OglRc = wglCreateContext(GfxDc)
                        
                        IF ISFALSE(OglRc) THEN
                          DIALOG POST Hndl, %OGL_ERROR, 3, 0
                          EXIT FUNCTION
                        END IF
                        
                        t = wglMakeCurrent(GfxDc, OglRc)
                        
                        IF ISFALSE(t) THEN
                          DIALOG POST Hndl, %OGL_ERROR, 4, 0
                          EXIT FUNCTION
                        END IF
                        
                        SetOglPipe = OglRc
                        END FUNCTION
                        
                        '----------------------------------------------------------------
                        '----------------------------------------------------------------
                        
                        SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                         BYVAL OrthoRange AS LONG)
                        
                        LOCAL ClearClr AS DWORD
                        
                        LOCAL Aspect AS SINGLE
                        LOCAL Xmin   AS SINGLE
                        LOCAL Ymin   AS SINGLE
                        LOCAL Xmax   AS SINGLE
                        LOCAL Ymax   AS SINGLE
                        LOCAL Zmin   AS SINGLE
                        LOCAL Zmax   AS SINGLE
                        
                        '=================================================================
                        ' This defines the graphics environment.
                        ' Getting this correct is crucial to using OpenGL.
                        '
                        ' gluOrtho2D is equivalent to using glOrtho with the FAR
                        ' parameter set to -1 and the NEAR parameter set to 1
                        '=================================================================
                        
                        ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                   %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                        
                        IF Wide <= High THEN
                          Aspect! = High / Wide
                        ELSE
                          Aspect! = Wide / High
                        END IF
                        
                        IF Wide <= High THEN
                          Xmin = -OrthoRange / 2
                          Xmax = OrthoRange  / 2
                          Ymin = (-OrthoRange / 2) * Aspect!
                          Ymax = (OrthoRange / 2) * Aspect!
                        ELSE
                          Xmin = (-OrthoRange / 2) * Aspect!
                          Xmax = (OrthoRange / 2) * Aspect!
                          Ymin = (-OrthoRange / 2)
                          Ymax = (OrthoRange  / 2)
                        END IF
                        
                        Zmin = -OrthoRange / 2
                        Zmax = OrthoRange
                        
                        glViewport(0, 0, Wide, High)
                        glMatrixMode(%GL_PROJECTION)
                        glLoadIdentity
                        glOrtho(-200, 200, -200, 200, -200, 200)
                        'glFrustum(0, 0, 0, 0, .1, 3)
                        'gluPerspective(0, 0, .00, 0)
                        'glLoadIdentity
                        glMatrixMode(%GL_MODELVIEW)
                        glLoadIdentity
                        glClear(ClearClr)
                        
                        
                        END SUB
                        
                        '----------------------------------------------------------------
                        '----------------------------------------------------------------
                        
                        SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
                        
                        wglMakeCurrent(0, 0)
                        wglDeleteContext(OglRc)
                        ReleaseDc(GfxHndl,GfxDc)
                        
                        END SUB
                        
                        '----------------------------------------------------------------
                        '----------------------------------------------------------------
                        
                        SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                            GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                        
                        LOCAL tRect AS WinRect_STRUCT
                        
                        GfxHndl = GetDlgItem(Hndl, %GFX_WIN)
                        GetClientRect(GfxHndl, tRect)
                        Wide = tRect.Brx
                        High = tRect.Bry
                        GfxDc = GetDc(GfxHndl)
                        
                        END SUB
                        
                        '-----------------------------------------------------------------
                        '-----------------------------------------------------------------
                        
                        SUB OglRenderImage(BYVAL X AS SINGLE, BYVAL Y AS SINGLE, BYVAL Z AS SINGLE, _
                                           tColor() AS RGB_STRUCT, tPnts() AS RGBA_STRUCT, _
                                           tNormal() AS RGBA_STRUCT)
                        
                        '==================================================================
                        ' This draws the picture.
                        '
                        ' The only way OpenGL can render color highlight properties is by
                        ' using a unit vector for a polygon.  The unit normals for the
                        ' polygons were precalculated and are stored in array tNormal()
                        '
                        ' Ambient light only can be rendered without using unit normals
                        '
                        '==================================================================
                        
                        LOCAL ClearClr AS DWORD
                        
                        LOCAL UbPnts  AS WORD
                        LOCAL Idx     AS WORD
                        
                        LOCAL VNormal() AS SINGLE
                        
                        UbPnts = UBOUND(tPnts)
                        
                        glPushMatrix
                        
                        glRotateF(X, 0.001!, 0, 0)
                        glRotateF(Y, 0, 0.001!, 0)
                        glRotateF(Z, 0, 0, 0.001!)
                        
                        glBegin(%GL_QUADS)
                        
                          FOR I = 1 TO UbPnts
                            IF tPnts(I).A = 1.0! THEN
                              Idx = tPnts(I).R
                              glColor3Ub(tColor(Idx).R, tColor(Idx).G, tColor(Idx).B)
                              ITERATE FOR
                            END IF
                            IF tFlags.Lite > 0 THEN
                              IF tPnts(I).A < 0.0! THEN
                                REDIM VNormal(2)              ' A normal was found, so use it to
                                Idx = -tPnts(I).A             ' render highlights on the object
                                VNormal(0) = tNormal(Idx).R
                                VNormal(1) = tNormal(Idx).G
                                VNormal(2) = tNormal(Idx).B
                                glNormal3FV(VNormal(0))
                              END IF
                            END IF
                            glVertex3F(tPnts(I).R, tPnts(I).G, tPnts(I).B)
                          NEXT I
                        glEnd
                        
                        glPopMatrix
                        
                        END SUB
                        
                        '-------------------------------------------------------------------
                        '-------------------------------------------------------------------
                        
                        SUB WindowToProjection(X1 AS SINGLE, Y1 AS SINGLE, Z1 AS SINGLE)
                        
                        LOCAL WinViewport()   AS LONG
                        LOCAL ModleMatrix()   AS DOUBLE
                        LOCAL ProjectMatrix() AS DOUBLE
                        
                        LOCAL WinX AS DOUBLE
                        LOCAL WinY AS DOUBLE
                        LOCAL WinZ AS DOUBLE
                        LOCAL X    AS DOUBLE
                        LOCAL Y    AS DOUBLE
                        LOCAL Z    AS DOUBLE
                        
                        DIM WinViewPort(0 TO 1, 0 TO 1)
                        DIM ModleMatrix(0 TO 3, 0 TO 3)
                        DIM ProjectMatrix(0 TO 3, 0 TO 3)
                        
                        X = X1
                        Y = Y1
                        Z = Z1
                        
                        glGetIntegerV(%GL_VIEWPORT, WinViewport(0))
                        glGetDoubleV(%GL_MODELVIEW_MATRIX, ModleMatrix(0))
                        glGetDoubleV(%GL_PROJECTION_MATRIX, ProjectMatrix(0))
                        gluUnProject(X, Y, Z, ModleMatrix(0), ProjectMatrix(0), WinViewPort(0), WinX, WinY, WinZ)
                        
                        X1 = WinX
                        Y1 = WinY
                        Z1 = WinZ
                        
                        END SUB
                        
                        '---------------------------------------------------------
                        '---------------------------------------------------------
                        
                        FUNCTION FnGfx_Ctl_CB(BYVAL Hndl AS LONG, BYVAL Msg AS LONG, _
                                              BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                        
                        LOCAL DlgHndl   AS DWORD
                        LOCAL CtlId     AS DWORD
                        
                        STATIC TickCount AS DWORD
                        
                        LOCAL ParamW  AS LONG
                        LOCAL ParamL  AS LONG
                        
                        LOCAL BmpStr  AS STRING
                        
                        LOCAL CurDrw  AS BYTE
                        LOCAL CurLvl  AS BYTE
                        
                        LOCAL WordPtr AS WORD POINTER
                        
                        'CurDrw = tFlags.CurDrw
                        'CurLvl = tInfo(CurDrw).CurLvl
                        'DlgHndl = tInfo(CurDrw).DlgHnd
                        'CtlId = tInfo(CurDrw).GfxId
                        'GfxHndl = tInfo(CurDrw).GfxHnd
                        
                        SELECT CASE AS LONG Msg
                          WordPtr = VARPTR(lParam)
                          CASE %WM_ERASEBKGND
                        '    ParamW = GetDlgCtrlId(Hndl) - %GFX
                        '    CALL Refresh(wParam, Hndl, ParamW)
                        '    FUNCTION = 0
                        '    EXIT FUNCTION
                        
                          CASE %WM_LBUTTONDOWN
                            tMouse.Mx = @WordPtr[0]
                            tMouse.My = @WordPtr[1]
                            tMouse.LbDown = 1
                            tMouse.LbUp = 0
                            tMouse.RbDown = 0
                        '    FUNCTION = 0
                        '    EXIT FUNCTION
                        
                          CASE %WM_LBUTTONUP
                            tMouse.Mx = @WordPtr[0]
                            tMouse.My = @WordPtr[1]
                            tMouse.LbDown = 0
                            tMouse.LbUp = 1
                            tMouse.RbDown = 0
                            tMouse.RbUp = 0
                        '    FUNCTION = 0
                        '    EXIT FUNCTION
                        
                          CASE %WM_RBUTTONDOWN
                            tMouse.Mx = @WordPtr[0]
                            tMouse.My = @WordPtr[1]
                            tMouse.LbDown = 0
                            tMouse.LbUp = 0
                            tMouse.RbDown = 1
                            tMouse.RbUp = 0
                        '    FUNCTION = 0
                        '    EXIT FUNCTION
                        
                          CASE %WM_RBUTTONUP
                            tMouse.Mx = @WordPtr[0]
                            tMouse.My = @WordPtr[1]
                            tMouse.LbDown = 0
                            tMouse.LbUp = 0
                            tMouse.RbDown = 0
                            tMouse.RbUp = 1
                        '    function = 0
                        '    exit function
                        
                          CASE %WM_MOUSEMOVE
                            IF (wParam AND %MK_LBUTTON) = %MK_LBUTTON THEN
                              tMouse.Mx = @WordPtr[0]
                              tMouse.My = @WordPtr[1]
                              tMouse.LbDown = 1
                              tMouse.LbUp = 0
                              tMouse.RbDown = 0
                              tMouse.RbUp = 0
                        '      function = 0
                        '      exit function
                            END IF
                        
                        END SELECT
                        FUNCTION = DefWindowProc(Hndl, Msg, wParam, lParam)
                        END FUNCTION
                        
                        '-----------------------------------------------------------
                        '-----------------------------------------------------------
                        
                        SUB RegWindow(Nam AS ASCIIZ, BYVAL Styl AS DWORD, BYVAL Code_Ptr AS DWORD, _
                                                 BYVAL Inst AS DWORD, BYVAL BkBrush AS DWORD, RegOk AS BYTE)
                        
                        LOCAL tWindow AS WNDCLASSEX
                        
                        tWindow.cbSize        = SIZEOF(tWindow)
                        tWindow.style         = Styl
                        tWindow.lpfnWndProc   = Code_Ptr
                        tWindow.cbClsExtra    = 0
                        tWindow.cbWndExtra    = 32
                        tWindow.hInstance     = Inst
                        tWindow.hIcon         = %NULL
                        tWindow.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                        
                        IF BkBrush = 0 THEN
                          tWindow.hbrBackground = 0
                        ELSE
                          tWindow.hbrBackground = GetStockObject(BkBrush)
                        END IF
                        
                        tWindow.lpszMenuName  = %NULL
                        tWindow.lpszClassName = VARPTR(Nam$)
                        tWindow.hIconSm       = %NULL
                        
                        Styl = RegisterClassEx(tWindow)
                        
                        IF Styl THEN RegOk = 1
                        
                        END SUB
                        
                        '----------------------------------------------------
                        '----------------------------------------------------
                        
                        SUB MakeWindow(BYVAL StyleX AS DWORD, WinClass AS ASCIIZ, Title AS ASCIIZ, _
                                       BYVAL Styl AS DWORD, BYVAL X1 AS DWORD, BYVAL Y1 AS DWORD, _
                                       BYVAL X2 AS DWORD, BYVAL Y2 AS DWORD, BYVAL Owner AS DWORD, _
                                       BYVAL CtlNum AS DWORD, BYVAL Inst AS DWORD, Hndl AS DWORD)
                        
                        Hndl = CreateWindowEx(StyleX, _       ' extended Window style
                                              WinClass$, _    ' window class name
                                              Title$, _       ' window caption
                                              Styl, _         ' window style
                                              X1, _           ' initial x position
                                              Y1, _           ' initial y position
                                              X2, _           ' initial x size
                                              Y2, _           ' initial y size
                                              Owner, _        ' parent window handle
                                              BYVAL CtlNum, _ ' window menu handle
                                              Inst, _         ' program instance handle
                                              BYVAL %NULL)    ' creation parameters
                        
                        END SUB
                        
                        '---------------------------------------------------------------
                        '---------------------------------------------------------------
                        
                        SUB FindPolyNormal(Vector3() AS SINGLE, PNormal() AS SINGLE)
                        
                        '=======================================================================
                        ' A normal vector can be found from any 3 points of a polygon, provided
                        ' that the polygon is a "valid" one as defined by OpenGL.
                        '
                        ' So what's a normal vector?  Simply put it is a line perpendicular to
                        ' the surface of a plane, ergo, "normal" to the plane.
                        '
                        ' This routine was lifted from the OpenGL super bible, 2nd edition.
                        '========================================================================
                        
                        LOCAL Vector1() AS SINGLE
                        LOCAL Vector2() AS SINGLE
                        
                        DIM Vector1(2)
                        DIM Vector2(2)
                        
                        Vector1!(0) = Vector3!(0, 0) - Vector3!(1, 0)
                        Vector1!(1) = Vector3!(0, 1) - Vector3!(1, 1)
                        Vector1!(2) = Vector3!(0, 2) - Vector3!(1, 2)
                        
                        Vector2!(0) = Vector3!(1, 0) - Vector3!(2, 0)
                        Vector2!(1) = Vector3!(1, 1) - Vector3!(2, 1)
                        Vector2!(2) = Vector3!(1, 2) - Vector3!(2, 2)
                        
                        PNormal!(0) = Vector1!(1) * Vector2!(2) - Vector1!(2) * Vector2!(1)
                        Pnormal!(1) = Vector1!(2) * Vector2!(0) - Vector1!(0) * Vector2!(2)
                        Pnormal!(2) = Vector1!(0) * Vector2!(1) - Vector1!(1) * Vector2!(0)
                        
                        END SUB
                        
                        '-----------------------------------------------------------------
                        '-----------------------------------------------------------------
                        
                        SUB FindUnitNormal(NormalV() AS SINGLE)
                        
                        '==================================================================
                        ' This routine finds the "unit" normal from a normal vector.
                        '
                        ' So what's a "unit" normal?  It's the same thing as a normal
                        ' vector but reduced to the range + 1 to -1.
                        '
                        ' This routine was lifted from the OpenGL super bible, 2nd edition
                        '==================================================================
                        
                        LOCAL Length AS SINGLE
                        
                        Length! = SQR(NormalV!(0) * NormalV!(0) + _
                                      NormalV!(1) * NormalV!(1) + _
                                      NormalV!(2) * NormalV!(2))
                        
                        IF Length! = 0.0! THEN
                          Length! = 1.0!
                        END IF
                        
                        NormalV!(0) = NormalV!(0) / Length!
                        NormalV!(1) = NormalV!(1) / Length!
                        NormalV!(2) = NormalV!(2) / Length!
                        
                        END SUB
                        
                        '----------------------------------------------------------------
                        '----------------------------------------------------------------
                        
                        SUB Lite_Properties(Ambient() AS SINGLE, Diffusion() AS SINGLE, MatReflect() AS SINGLE, _
                                                   SpecReflect() AS SINGLE, LitePosn AS SINGLE, _
                                                   LiteExponent AS INTEGER)
                        
                          IF tFlags.AIncRed THEN Ambient(0) = Ambient(0) + 0.001!
                          IF tFlags.AIncGreen THEN Ambient(1) = Ambient(1) + 0.001!
                          IF tFlags.AIncBlue THEN Ambient(2) = Ambient(2) + 0.001!
                        
                          IF Ambient(0) > 1.0! THEN Ambient(0) = 1.0!
                          IF Ambient(1) > 1.0! THEN Ambient(1) = 1.0!
                          IF Ambient(2) > 1.0! THEN Ambient(2) = 1.0!
                        
                          IF tFlags.ADecRed THEN Ambient(0) = Ambient(0) - 0.001!
                          IF tFlags.ADecGreen THEN Ambient(1) = Ambient(1) - 0.001!
                          IF tFlags.ADecBlue THEN Ambient(2) = Ambient(2) - 0.001!
                        
                          IF Ambient(0) < 0.0! THEN Ambient(0) = 0.0!
                          IF Ambient(1) < 0.0! THEN Ambient(1) = 0.0!
                          IF Ambient(2) < 0.0! THEN Ambient(2) = 0.0!
                        
                          IF tFlags.ADefault THEN MAT Ambient() = CON
                        
                          IF tFlags.MIncRed THEN Diffusion(0) = Diffusion(0) + 0.001!
                          IF tFlags.MIncGreen THEN Diffusion(1) = Diffusion(1) + 0.001!
                          IF tFlags.MIncBlue THEN Diffusion(2) = Diffusion(2) + 0.001!
                        
                          IF Diffusion(0) > 1.0! THEN Diffusion(0) = 1.0!
                          IF Diffusion(1) > 1.0! THEN Diffusion(1) = 1.0!
                          IF Diffusion(2) > 1.0! THEN Diffusion(2) = 1.0!
                        
                          IF tFlags.MDecRed THEN Diffusion(0) = Diffusion(0) - 0.001!
                          IF tFlags.MDecGreen THEN Diffusion(1) = Diffusion(1) - 0.001!
                          IF tFlags.MDecBlue THEN Diffusion(2) = Diffusion(2) - 0.001!
                        
                          IF Diffusion(0) < 0.0! THEN Diffusion(0) = 0.0!
                          IF Diffusion(1) < 0.0! THEN Diffusion(1) = 0.0!
                          IF Diffusion(2) < 0.0! THEN Diffusion(2) = 0.0!
                        
                          IF tFlags.MDefault THEN MAT Diffusion() = CON
                        
                          IF tFlags.MRefIncRed THEN MatReflect(0) = MatReflect(0) + 0.001!
                          IF tFlags.MRefIncGreen THEN MatReflect(1) = MatReflect(1) + 0.001!
                          IF tFlags.MRefIncBlue THEN MatReflect(2) = MatReflect(1) + 0.001!
                        
                          IF MatReflect(0) > 1.0! THEN MatReflect(0) = 1.0!
                          IF MatReflect(1) > 1.0! THEN MatReflect(1) = 1.0!
                          IF MatReflect(2) > 1.0! THEN MatReflect(2) = 1.0!
                        
                          IF tFlags.MRefDecRed THEN MatReflect(0) = MatReflect(0) - 0.001!
                          IF tFlags.MRefDecGreen THEN MatReflect(1) = MatReflect(1) - 0.001!
                          IF tFlags.MRefDecBlue THEN MatReflect(2) = MatReflect(2) - 0.001!
                        
                          IF MatReflect(0) < 0.0! THEN MatReflect(0) = 0.0!
                          IF MatReflect(1) < 0.0! THEN MatReflect(1) = 0.0!
                          IF MatReflect(2) < 0.0! THEN MatReflect(2) = 0.0!
                        
                          IF tFlags.MRefDefault  THEN MAT MatReflect() = CON
                        
                          IF tFlags.SpecIncRed THEN SpecReflect(0) = SpecReflect(0) + 0.001
                          IF tFlags.SpecIncGreen THEN SpecReflect(1) = SpecReflect(1) + 0.001
                          IF tFlags.SpecIncBlue THEN SpecReflect(2) = SpecReflect(2) + 0.001
                        
                          IF SpecReflect(0) > 1.0! THEN SpecReflect(0) = 1.0!
                          IF SpecReflect(1) > 1.0! THEN SpecReflect(1) = 1.0!
                          IF SpecReflect(2) > 1.0! THEN SpecReflect(2) = 1.0!
                        
                          IF tFlags.SpecDecRed THEN SpecReflect(0) = SpecReflect(0) - 0.001
                          IF tFlags.SpecDecGreen THEN SpecReflect(1) = SpecReflect(1) - 0.001
                          IF tFlags.SpecDecBlue THEN SpecReflect(2) = SpecReflect(2) - 0.001
                        
                          IF SpecReflect(0) < 0.0! THEN SpecReflect(0) = 0.0!
                          IF SpecReflect(1) < 0.0! THEN SpecReflect(1) = 0.0!
                          IF SpecReflect(2) < 0.0! THEN SpecReflect(2) = 0.0!
                        
                          IF tFlags.SpecDefault THEN MAT SpecReflect() = CON
                        
                          IF tFlags.SpecHiliteInc THEN LiteExponent = LiteExponent + 1
                          IF tFlags.SpecHiliteDec THEN LiteExponent = LiteExponent - 1
                          IF tFlags.SpecHiliteDefault THEN LiteExponent = 128
                        
                          IF tFlags.SDefInc THEN LitePosn = LitePosn + 0.001!
                          IF tFlags.SDefDec THEN LitePosn = LitePosn - 0.001!
                        
                          IF LitePosn > 1.0! THEN LitePosn = 1.0!
                          IF LitePosn < 0.0! THEN LitePosn = 0.0!
                        
                          IF tFlags.SDefDefault THEN LitePosn = 1.0!
                        
                        END SUB
                        
                        '-----------------------------------------------------------
                        '-----------------------------------------------------------
                        
                        SUB Ambient_Light(Ambient() AS SINGLE)
                        
                        '=============================================================
                        ' Sets-up ambient light only.
                        ' Ambient light is light from all directions.  Basically it is
                        ' reflected light from the atmosphere, walls, ground (albedo),
                        ' and other objects.
                        '=============================================================
                        
                        glEnable(%GL_LIGHTING)
                        glLightModelFV(%GL_LIGHT_MODEL_AMBIENT, Ambient(0))
                        glEnable(%GL_COLOR_MATERIAL)
                        glColorMaterial(%GL_FRONT, %GL_AMBIENT_AND_DIFFUSE)
                        
                        END SUB
                        
                        '----------------------------------------------------------
                        '----------------------------------------------------------
                        
                        SUB Spec_Light(Ambient() AS SINGLE, Diffusion() AS SINGLE, _
                                       MatReflect() AS SINGLE, SpecReflect() AS SINGLE, _
                                       LightPosn() AS SINGLE, BYVAL LiteExponent AS INTEGER)
                        
                        '==============================================================
                        ' Sets-up the ability to highlight an object.
                        '
                        ' Highlights are created when lightrays are reflected from a surface
                        ' to the eyes of the viewer.  They are a function of the light
                        ' wave lengths and the wave length absorbant properties of the surface.
                        ' For example, a blue tinted light may be reflected if the light contains
                        ' a blue wave length component and the surface absorbs most of the other
                        ' wave lengths.
                        '==============================================================
                        
                        glEnable(%GL_LIGHTING)
                        glLightFV(%GL_LIGHT0, %GL_AMBIENT, Ambient(0))
                        glLightFV(%GL_LIGHT0, %GL_DIFFUSE, Diffusion(0))
                        glLightFV(%GL_LIGHT0, %GL_SPECULAR, MatReflect(0))
                        glLightFV(%GL_LIGHT0, %GL_POSITION, LightPosn(0))
                        glEnable(%GL_LIGHT0)
                        glEnable(%GL_COLOR_MATERIAL)                         'Enables color tracking
                        glColorMaterial(%GL_FRONT, %GL_AMBIENT_AND_DIFFUSE)  'Sets material properties
                        glMaterialFV(%GL_FRONT, %GL_SPECULAR, SpecReflect(0))'Designated polygons will reflect.
                        glMaterialI(%GL_FRONT, %GL_SHININESS, LiteExponent)  'Modrates shine
                        
                        END SUB
                        
                        '-----------------------------------------------------------------------------
                        '-----------------------------------------------------------------------------
                        
                        SUB Obj_Data(Obj_Points() AS RGBA_STRUCT)
                        
                        LOCAL Dcount AS WORD
                        
                        '=======================================================
                        '                      Color Data
                        '-------------------------------------------------------
                        ' The first number is the index to the color array
                        ' The second number is a flag to indicate that color
                        ' should be used at this vertex
                        '-------------------------------------------------------
                        
                        DATA   1,   0,  0, 1
                        
                        '========================================================
                        '                      Vector Data
                        '--------------------------------------------------------
                        ' The negative number indicates that a unit normal
                        ' vector is calculated for this polygon.  The value
                        ' of the negative number is the index to the unit
                        ' normal array
                        '--------------------------------------------------------
                        
                        DATA -10,  50,  0, -1
                        
                        '========================================================
                        
                        DATA  10,  50,  0, 0
                        DATA  50, -50,  0, 0
                        DATA -50, -50,  0, 0
                        
                        DATA   2,   0,  0, 1
                        DATA  50, -50,  0, -2
                        DATA -50, -50,  0, 0
                        DATA -50, -50, 50, 0
                        DATA  50, -50, 50, 0
                        
                        DATA   3,   0,  0, 1
                        DATA -10,  50, 50, 0
                        DATA   4,   0,  0, 1
                        DATA  10,  50, 50, 0
                        DATA   5,   0,  0, 1
                        DATA  50, -50, 50, 0
                        DATA -50, -50, 50, 0
                        
                        DATA   6,   0,  0, 1
                        DATA -10,  50, 50, -3
                        DATA   7,   0,  0, 1
                        DATA -50, -50, 50, 0
                        DATA   8,   0,  0, 1
                        DATA -50, -50,  0, 0
                        DATA   9,   0,  0, 1
                        DATA -10,  50,  0, 0
                        
                        Dcount = DATACOUNT
                        
                        REDIM ObJ_Points(1 TO Dcount \ 4)
                        
                        FOR I = 1 TO DCount STEP 4
                          INCR J
                          Obj_Points(J).R = VAL(READ$(I))
                          Obj_Points(J).G = VAL(READ$(I + 1))
                          Obj_Points(J).B = VAL(READ$(I + 2))
                          Obj_Points(J).A = VAL(READ$(I + 3))
                        NEXT I
                        END SUB
                        
                        '-----------------------------------------------
                        '-----------------------------------------------
                        
                        SUB Color_Data(Kolor() AS RGB_STRUCT)
                        
                        LOCAL Dcount AS WORD
                        
                        DATA 255, 128,   0
                        DATA 255, 190,   0
                        DATA 128, 128, 180
                        DATA 128, 128, 180
                        DATA 255, 190,   0
                        DATA 128, 128, 180
                        DATA 128, 128, 180
                        DATA 128, 128, 180
                        DATA 255, 128,   0
                        
                        Dcount = DATACOUNT
                        
                        REDIM Kolor(1 TO Dcount \ 3)
                        
                        FOR I = 1 TO DCount STEP 3
                          INCR J
                          Kolor(J).R = VAL(READ$(I))
                          Kolor(J).G = VAL(READ$(I + 1))
                          Kolor(J).B = VAL(READ$(I + 2))
                        NEXT I
                        
                        END SUB
                        
                        '-------------------------------------------------
                        '-------------------------------------------------
                        
                        SUB LightPos(tMpos AS Single2_STRUCT)
                        
                        MSGBOX "Select light position with the mouse"
                        
                        RESET tMouse
                        DO
                          DIALOG DOEVENTS
                        LOOP UNTIL tMouse.LbDown
                        tMpos.Mx = tMouse.Mx
                        tMpos.My = tMouse.My
                        
                        END SUB
                        
                        '--------------------------------------------------
                        '--------------------------------------------------
                        
                        SUB Zdepth
                        
                        MSGBOX "Hold left mouse button down and move the cursor up or down" + $CRLF + $CRLF + _
                               "UP = into screen"+ $CRLF + _
                               "DOWN = out of screen"
                        
                        RESET tMouse
                        DO
                          DIALOG DOEVENTS
                          IF tMouse.LbDown THEN
                            DO
                              DIALOG DOEVENTS
                            LOOP UNTIL tMouse.LbUp
                            EXIT DO
                          END IF
                        LOOP
                        
                        END SUB
                        
                        '-------------------------------------------------------
                        '-------------------------------------------------------
                        
                        SUB GetNormals(tPnts() AS RGBA_STRUCT, tNormal() AS RGBA_STRUCT)
                        
                        '================================================================
                        ' This routine seperates the wheat from the chaff to create
                        ' vectors to use for rendering
                        '================================================================
                        
                        LOCAL DCount AS WORD
                        LOCAL NCount AS WORD
                        LOCAL VCount AS WORD
                        
                        LOCAL Vector()  AS SINGLE
                        LOCAL PNormal() AS SINGLE
                        
                        DIM Vector(2, 2)
                        DIM pNormal(2)
                        
                        DCount = UBOUND(tPnts)
                        
                        FOR I = 1 TO DCount
                          IF tPnts(I).A = 1.0! THEN ITERATE FOR
                          IF tPnts(I).A < 0.0! THEN
                            VCount = 1
                            NCount = -tPnts(I).A
                          END IF
                        
                          IF VCount > 3 THEN ITERATE FOR          ' Since only 3 vectors are required,
                                                                  ' skip until another vector requirement
                          Vector(VCount - 1, 0) = tPnts(I).R
                          Vector(VCount - 1, 1) = tPnts(I).G
                          Vector(VCount - 1, 2) = tPnts(I).B
                          INCR VCount
                          IF VCount > 3 THEN
                            CALL FindPolyNormal(Vector(), PNormal())
                            CALL FindUnitNormal(PNormal())
                            REDIM PRESERVE tNormal(1 TO Ncount)
                            tNormal(NCount).R = PNormal(0)
                            tNormal(NCount).G = PNormal(1)
                            tNormal(NCount).B = PNormal(2)
                            ITERATE FOR
                          END IF
                        NEXT I
                        END SUB
                        Walt Decker

                        Comment


                        • #13
                          What About a Spot Light?

                          Spot lights are pretty much like specular light except more attenuated. Also, with a spot light it appears that OpenGL calculates the face normals for you. That, in itself, makes them easier than specular light.

                          Couple of things you should keep in mind:

                          The fourth element of the spot light position array, along with the shininess of the object governs the size of the spot.

                          If the third element of the spot light position array is negative, the third element of the spot light direction array should be positive.

                          The below example uses GLAUX.DLL to create solid spheres and a solid cone. If you don't have GLAUX.DLL you can use glSphere() and an algo to draw a cone when positioning the spot.

                          The sphere in the example appears egg-shaped because in the Ogl window setup routine the aspect ratio is ignored.

                          The pertinent subs/functions have comments. Anyway, here's the example:

                          Code:
                          '=======================================================================
                          '                            OPENGL FUNCTIONS USED
                          '=======================================================================
                          ' glViewport()
                          ' glMatrixMode()
                          ' glLoadIdentity
                          ' glOrtho()
                          ' glMatrixMode()
                          ' glclear()
                          ' glPushMatrix
                          ' glColor3Ub()
                          ' glBegin()
                          ' glEnd
                          ' glVertex3F()
                          ' glPopMatrix
                          ' glFlush
                          ' glEnable()
                          ' glLightFV()
                          ' glLightF()
                          ' glTranslateF()
                          ' glColorMaterial()
                          ' glMaterialFV()
                          ' glMaterialI()
                          ' glPushAttrib()
                          ' glPopAttrib()
                          ' glLightModelFV()
                          ' auxSolidSphere()
                          ' auxSolidCone()
                          '=========================================================================
                          '                            WINDOWS FUNCTIONS USED
                          '=========================================================================
                          ' GetDc
                          ' ReleaseDc
                          ' ChoosePixelFormat
                          ' SetPixelFormat
                          ' wglCreateContext
                          ' wglMakeCurrent
                          ' wglDeleteContext
                          '=========================================================================
                          
                          #COMPILE EXE
                          
                          DEFLNG A - Z
                          
                          #INCLUDE "WIN32API.INC"
                          #INCLUDE "pbforms.inc"
                          #INCLUDE "gl.inc"
                          #INCLUDE "glu.inc"
                          #INCLUDE "glaux.inc"
                          
                          TYPE RGB_STRUCT
                            R AS BYTE
                            G AS BYTE
                            B AS BYTE
                          END TYPE
                          
                          TYPE Vertex_STRUCT
                            X AS SINGLE
                            Y AS SINGLE
                            Z AS SINGLE
                            W AS SINGLE
                          END TYPE
                          
                          TYPE WinRect_STRUCT
                            Ulx AS LONG
                            Uly AS LONG
                            Brx AS LONG
                            Bry AS LONG
                          END TYPE
                          
                          TYPE OglFlag_STRUCT
                            EndProg     AS BIT * 1 IN BYTE
                            Busy        AS BIT * 1
                            Sphere      AS BIT * 1
                            Cube        AS BIT * 1
                            Stars       AS BIT * 1
                          END TYPE
                          
                          TYPE Single2_STRUCT
                            Mx      AS SINGLE
                            My      AS SINGLE
                          END TYPE
                          
                          TYPE Mouse_Btn_STRUCT
                            LbDown  AS BIT * 1 IN BYTE
                            LbUp    AS BIT * 1
                            RbDown  AS BIT * 1
                            RbUp    AS BIT * 1
                          END TYPE
                          
                          TYPE Mouse_STRUCT
                            Single2_STRUCT
                            Mouse_Btn_STRUCT
                          END TYPE
                          
                          %GFX_WIN     =    5
                          %BTN_END     =    6
                          %BTN_OGL     =    7
                          %LBL_STATUS  =    8
                          
                          %MNU_ROTATESPHERE = 10
                          %MNU_ADDCUBE      = 11
                          
                          %OGL_ERROR   = %WM_USER + 500
                          
                          %TEST        = 0
                          
                          GLOBAL MnuHndl AS DWORD
                          
                          GLOBAL tFlags AS OglFlag_STRUCT
                          GLOBAL tMouse AS Mouse_STRUCT
                          
                          DECLARE SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR, BYVAL Flag AS BYTE)
                          DECLARE SUB RunOgl(BYVAL Hndl AS DWORD)
                          DECLARE SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                                      GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                          
                          DECLARE SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                           BYVAL OrthoRange AS LONG)
                          
                          DECLARE SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, _
                                                  BYVAL GfxHndl AS DWORD)
                          
                          DECLARE SUB FindPolyNormal(Vector3() AS SINGLE, PNormal() AS SINGLE)
                          DECLARE SUB FindUnitNormal(NormalV() AS SINGLE)
                          
                          DECLARE FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                                      tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                          
                          DECLARE FUNCTION PBMAIN() AS LONG
                          
                          DECLARE CALLBACK FUNCTION Main_CB()
                          
                          '----------------------------------------------------------------------
                          '----------------------------------------------------------------------
                          CALLBACK FUNCTION Mnu_CB()
                          
                          IF CBMSG = %WM_COMMAND THEN
                            IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                          
                              SELECT CASE CBCTL
                                CASE %MNU_ROTATESPHERE
                                  IF tFlags.Sphere THEN
                                    tFlags.Sphere = 0
                                    MENU SET STATE MnuHndl, BYCMD %MNU_ROTATESPHERE, %MF_UNCHECKED OR %MF_ENABLED
                                  ELSE
                                    tFlags.Sphere = 1
                                    MENU SET STATE MnuHndl, BYCMD %MNU_ROTATESPHERE, %MF_CHECKED OR %MF_ENABLED
                                  END IF
                          
                                CASE %MNU_ADDCUBE
                                  IF tFlags.Cube THEN
                                    tFlags.Cube = 0
                                    MENU SET STATE MnuHndl, BYCMD %MNU_ADDCUBE, %MF_UNCHECKED OR %MF_ENABLED
                                  ELSE
                                    tFlags.Cube = 1
                                    MENU SET STATE MnuHndl, BYCMD %MNU_ADDCUBE, %MF_CHECKED OR %MF_ENABLED
                                  END IF
                          
                              END SELECT
                            END IF
                          END IF
                          '
                          END FUNCTION
                          
                          '-----------------------------------------------------------
                          '-----------------------------------------------------------
                          
                          FUNCTION PBMAIN()
                          
                          LOCAL hDlg AS DWORD
                          LOCAL hPopUp1 AS DWORD
                          
                          DIALOG NEW PIXELS, 0, "Exploring Ogl - A Little Spot Light", , , 420, 290, _
                                            %WS_POPUP OR %WS_BORDER _
                                            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                            %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                                            %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
                                            %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                          
                          CONTROL ADD BUTTON, hDlg, %BTN_END, "Close", 5, 225, 85, 20, %WS_CHILD _
                            OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                            %BS_NOTIFY OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                            %WS_EX_LTRREADING
                          
                          CONTROL ADD BUTTON, hDlg, %BTN_OGL, "Run Ogl", 120, 225, 75, 20, _
                            %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_DEFPUSHBUTTON _
                            OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR _
                            %WS_EX_LTRREADING
                          
                          DIALOG  SEND hDlg, %DM_SETDEFID, %BTN_OGL, 0
                          
                          
                          MENU NEW BAR TO MnuHndl
                          MENU NEW POPUP TO hPopUp1
                          MENU ADD POPUP, MnuHndl, "Rotate", hPopUp1, %MF_ENABLED
                            MENU ADD STRING, hPopUp1, "Sphere", %MNU_ROTATESPHERE, %MF_ENABLED, CALL Mnu_CB()
                          MENU NEW POPUP TO hPopUp1
                          MENU ADD POPUP, MnuHndl, "Add", hPopUp1, %MF_CHECKED
                            MENU ADD STRING, hPopUp1, "Cube", %MNU_ADDCUBE, %MF_ENABLED, CALL Mnu_CB()
                          
                          MENU ATTACH MnuHndl, hDlg
                          
                          DIALOG SHOW MODAL hDlg, CALL Main_CB
                          
                          END FUNCTION
                          
                          '------------------------------------------------------------
                          '------------------------------------------------------------
                          
                          CALLBACK FUNCTION Main_CB()
                          
                          LOCAL lParam AS LONG
                          LOCAL wParam AS LONG
                          
                          SELECT CASE AS LONG CBMSG
                          
                            wParam = CBWPARAM
                            CASE %WM_INITDIALOG
                              Inst = GetWindowLong(CBHNDL, %GWL_HINSTANCE)
                              Styl = %CS_HREDRAW OR %CS_VREDRAW OR %CS_OWNDC OR %CS_GLOBALCLASS
                          
                              CALL RegWindow("OglCtl" + $NUL, Styl, CODEPTR(FnGfx_Ctl_CB), Inst, %GRAY_BRUSH, 0)
                          
                              Styl = %WS_VISIBLE OR %WS_TABSTOP OR %WS_CHILD
                          
                              CONTROL ADD "OglCtl", CBHNDL, %GFX_WIN, "", 5, 25, 290, 190, Styl, %WS_EX_CLIENTEDGE
                          
                            CASE %WM_COMMAND
                              wParam = CBCTLMSG
                              SELECT CASE AS LONG wParam
                                CASE %BN_CLICKED, %STN_CLICKED, 1
                                  SELECT CASE AS LONG CBCTL
                                    CASE %GFX_WIN
                                      EXIT FUNCTION
                          
                                    CASE %BTN_END
                                      tFlags.EndProg = 1
                                      CALL RunOgl(CBHNDL)
                                      DIALOG END CBHNDL
                                      FUNCTION = 1
                                      EXIT FUNCTION
                          
                                    CASE %BTN_OGL
                                      IF tFlags.Busy THEN
                                        CONTROL SET TEXT CBHNDL, %BTN_OGL, "BUSY"
                                        EXIT SELECT
                                      ELSE
                                        CONTROL SET TEXT CBHNDL, %BTN_OGL, "Run Ogl"
                                      END IF
                                      tFlags.Busy = 1
                                      CALL RunOgl(CBHNDL)
                                      FUNCTION = 1
                                      EXIT FUNCTION
                          
                                  END SELECT
                              END SELECT
                          
                            CASE %WM_DESTROY
                              IF tFlags.EndProg THEN EXIT SELECT
                              tFlags.EndProg = 1
                              CALL RunOgl(CBHNDL)
                          
                            CASE %OGL_ERROR
                              SELECT CASE wParam
                                CASE 1
                                  MSGBOX "Could not find matching pixel format: error #" + STR$(wParam)
                                CASE 2
                                  MSGBOX "Could not set selected pixel format: error #" + STR$(wParam)
                                CASE 3
                                  MSGBOX "Could not create rendering context: error #" + STR$(wParam)
                                CASE 4
                                  MSGBOX "Could not make rendering context current.  Defined window may not" _
                                         + " support it: error #" + STR$(wParam)
                              END SELECT
                              DIALOG END CBHNDL
                          END SELECT
                          
                          END FUNCTION
                          
                          '------------------------------------------------------------
                          '------------------------------------------------------------
                          
                          SUB OglPixFormat(Pfd AS PIXELFORMATDESCRIPTOR, BYVAL Flag AS BYTE)
                          
                          '==============================================================
                          ' This is the 1st step in setting up windows for OpenGl support
                          ' %PFD_DOUBLEBUFFER seems to be required for OpenGl to display
                          ' graphics
                          '==============================================================
                          
                          LOCAL FlagParam AS DWORD
                          
                          IF Flag THEN
                            FlagParam = %PFD_DRAW_TO_WINDOW OR PFD_DRAW_TO_BITMAP OR %PFD_SUPPORT_OPENGL _
                                        OR %PFD_DOUBLEBUFFER
                          ELSE
                            FlagParam = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
                          END IF
                          
                          pfd.nsize = SIZEOF(PIXELFORMAPTDESCRIPTOR)
                          pfd.nversion = 1
                          pfd.dwflags = FlagParam
                          pfd.dwlayermask = %PFD_MAIN_PLANE
                          pfd.ipixeltype = %PFD_TYPE_RGBA
                          pfd.ccolorbits = 24
                          pfd.cdepthbits = 24
                          
                          END SUB
                          
                          '---------------------------------------------------------------
                          '---------------------------------------------------------------
                          
                          SUB RunOgl(BYVAL Hndl AS DWORD)
                          
                          STATIC Wide  AS LONG
                          STATIC High  AS LONG
                          
                          STATIC GfxDC     AS DWORD
                          STATIC OglRc     AS DWORD
                          STATIC GfxHndl   AS DWORD
                          
                          LOCAL ClearClr   AS DWORD
                          
                          LOCAL LiteExponent AS INTEGER
                          
                          LOCAL tPixFmt   AS PIXELFORMATDESCRIPTOR
                          LOCAL tRect     AS WinRect_STRUCT
                          LOCAL tColor()  AS RGB_STRUCT
                          LOCAL tPnts()   AS Vertex_STRUCT
                          
                          STATIC tStars()  AS Vertex_STRUCT
                          
                          LOCAL Ambient()     AS SINGLE
                          LOCAL Diffusion()   AS SINGLE
                          LOCAL MatReflect()  AS SINGLE
                          LOCAL SpecReflect() AS SINGLE
                          LOCAL LightPosn()   AS SINGLE
                          LOCAL LiteDir()     AS SINGLE
                          
                          STATIC X       AS SINGLE
                          STATIC Y       AS SINGLE
                          STATIC Z       AS SINGLE
                          STATIC Azi     AS SINGLE
                          STATIC TrasnX  AS SINGLE
                          STATIC TransY  AS SINGLE
                          STATIC TransZ  AS SINGLE
                          
                          STATIC FlipX  AS BYTE
                          STATIC FlipY  AS BYTE
                          STATIC FlipZ  AS BYTE
                          
                          IF ISFALSE(GfxDc) THEN
                            IF tFlags.EndProg THEN EXIT SUB
                            CALL GetGfxWinParams(Hndl, GfxHndl, GfxDc, Wide, High)
                            CALL OglPixFormat(tPixFmt, 0)
                          
                            OglRc = SetOglPipe(Hndl, GfxDc, tPixFmt)
                          
                            IF OglRc = 0 THEN EXIT SUB
                          
                            CALL SetOglWindow(Wide, High, 100)
                          ELSE
                            IF tFlags.EndProg THEN
                              CloseOpenGL(OglRc, GfxDc, GfxHndl)
                              EXIT SUB
                             END IF
                          END IF
                          
                          DIM Ambient!(3)
                          DIM Diffusion!(3)
                          DIM MatReflect!(3)
                          DIM SpecReflect!(3)
                          DIM LightPosn!(3)
                          DIM LiteDir!(2)
                          DIM tStars(1 TO 100)
                          
                          MAT Diffusion!()  = CON
                          MAT MatReflect!() = CON
                          MAT SpecReflect!() = CON
                          
                          ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                     %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                          
                          IF tFlags.Stars = 0 THEN
                            CALL Position_Stars(tStars())
                            X! = 10
                            Y! = 20
                            Azi! = 15
                            tFlags.Stars = 1
                          END IF
                          
                          CALL Color_Data(tColor())
                          CALL Obj_Data(tPnts())
                          
                          CALL AddLite(Ambient!(), Diffusion!(), MatReflect!(), SpecReflect!(), LightPosn!(), _
                                       LiteDir!())
                          
                          FOR I = 1 TO 360
                            CALL RenderSphere(X!, Y!, Z!)
                            IF tFlags.Cube THEN
                              CALL OglRenderImage(X!, Y!, Z!, TransX!, TransY!, TransZ!, tColor(), tPnts())
                            END IF
                            CALL RenderStars(tStars())
                            CALL SetSpot(X!, Y!, Azi!, LightPosn!(), LiteDir!())
                          
                            SwapBuffers(GfxDc)
                            glClear(ClearClr)
                            glFlush
                          
                            X! = X! + 5
                            Y! = Y! + 5
                            Axi! = Azi! - 5
                          
                            IF tFlags.Cube THEN
                              IF FlipX = 1 THEN
                                TransX! = TransX! + .5!
                                IF TransX! > 160! THEN
                                  TransX! = TransX! - .5!
                                  FlipX = 0
                                END IF
                              ELSE
                                TransX! = TransX! - .5!
                                IF TransX! < -160! THEN
                                  TransX! = TransX! + .5
                                  FlipX = 1
                                END IF
                              END IF
                          
                              IF FlipY = 1 THEN
                                TransY! = TransY! + .25!
                                IF TransY! > 15! THEN
                                  TransY! = TransY! - .25
                                  FlipY = 0
                                END IF
                              ELSE
                                TransY! = TransY! - .25
                                IF TransY! < -15! THEN
                                  TransY! = TransY! + .25
                                  FlipY = 1
                                END IF
                              END IF
                          
                              IF FlipZ = 1 THEN
                                TransZ! = TransZ! + 3!
                                IF TransZ! > 160! THEN
                                  TransZ! = TransZ! - 3
                                  FlipZ = 0
                                END IF
                              ELSE
                                TransZ! = TransZ! - 3
                                IF TransZ! < 160! THEN
                                  TransZ! = TransZ! + 3
                                  FlipZ = 1
                                END IF
                              END IF
                            END IF
                            DIALOG DOEVENTS
                            IF tFlags.EndProg THEN EXIT FOR
                          
                            SLEEP 200
                          NEXT I
                          
                          tFlags.Busy = 0
                          
                          glDisable(%GL_LIGHTING)
                          glDisable(%GL_DEPTH_TEST)
                          glDisable(%GL_COLOR_MATERIAL)
                          glDisable(%GL_LIGHT0)
                          glFlush
                          glFinish
                          
                          END SUB
                          
                          '----------------------------------------------------------------
                          '----------------------------------------------------------------
                          
                          FUNCTION SetOglPipe(BYVAL Hndl AS DWORD, BYVAL GfxDc AS DWORD, _
                                              tPixFmt AS PIXELFORMATDESCRIPTOR) AS LONG
                          
                          '================================================================
                          '  This is the second step for OpenGL support
                          '  ChoosePixelFormat selects a pixel format that matches that
                          '  described in the PIXELFORMATDESCRIPTOR structure.
                          '
                          '  Each step is the setup is quried because not all windows support
                          '  OpenGL rendering
                          '================================================================
                          
                          LOCAL PixFormat AS DWORD
                          LOCAL OglRc     AS DWORD
                          
                          LOCAL T AS LONG
                          
                          PixFormat = ChoosePixelFormat(GfxDc, tPixFmt)
                          
                          IF ISFALSE (PixFormat) THEN
                            DIALOG POST Hndl, %OGL_ERROR, 1, 0
                            EXIT FUNCTION
                          END IF
                          
                          t = SetPixelFormat(GfxDc, PixFormat, tPixFmt)
                          
                          IF ISFALSE(t) THEN
                            DIALOG POST Hndl, %OGL_ERROR, 2, 0
                            EXIT FUNCTION
                          END IF
                          
                          OglRc = wglCreateContext(GfxDc)
                          
                          IF ISFALSE(OglRc) THEN
                            DIALOG POST Hndl, %OGL_ERROR, 3, 0
                            EXIT FUNCTION
                          END IF
                          
                          t = wglMakeCurrent(GfxDc, OglRc)
                          
                          IF ISFALSE(t) THEN
                            DIALOG POST Hndl, %OGL_ERROR, 4, 0
                            EXIT FUNCTION
                          END IF
                          
                          SetOglPipe = OglRc
                          END FUNCTION
                          
                          '----------------------------------------------------------------
                          '----------------------------------------------------------------
                          
                          SUB SetOglWindow(BYVAL Wide AS LONG, BYVAL High AS LONG, _
                                           BYVAL OrthoRange AS LONG)
                          
                          LOCAL ClearClr AS DWORD
                          
                          LOCAL Aspect AS SINGLE
                          LOCAL Xmin   AS SINGLE
                          LOCAL Ymin   AS SINGLE
                          LOCAL Xmax   AS SINGLE
                          LOCAL Ymax   AS SINGLE
                          LOCAL Zmin   AS SINGLE
                          LOCAL Zmax   AS SINGLE
                          
                          '=================================================================
                          ' This defines the graphics environment.
                          ' Getting this correct is crucial to using OpenGL.
                          '
                          ' gluOrtho2D is equivalent to using glOrtho with the FAR
                          ' parameter set to -1 and the NEAR parameter set to 1
                          '=================================================================
                          
                          ClearClr = %GL_COLOR_BUFFER_BIT OR %GL_DEPTH_BUFFER_BIT OR _
                                     %GL_ACCUM_BUFFER_BIT OR %GL_STENCIL_BUFFER_BIT
                          
                          'IF Wide <= High THEN
                          '  Aspect! = High / Wide
                          'ELSE
                          '  Aspect! = Wide / High
                          'END IF
                          '
                          'IF Wide <= High THEN
                          '  Xmin = -OrthoRange / 2
                          '  Xmax = OrthoRange  / 2
                          '  Ymin = (-OrthoRange / 2) * Aspect!
                          '  Ymax = (OrthoRange / 2) * Aspect!
                          'ELSE
                          '  Xmin = (-OrthoRange / 2) * Aspect!
                          '  Xmax = (OrthoRange / 2) * Aspect!
                          '  Ymin = (-OrthoRange / 2)
                          '  Ymax = (OrthoRange  / 2)
                          'END IF
                          
                          Zmin = -OrthoRange / 2
                          Zmax = OrthoRange
                          
                          glViewport(0, 0, Wide, High)
                          glMatrixMode(%GL_PROJECTION)
                          glLoadIdentity
                          glOrtho(-200, 200, -200, 200, -200, 200)
                          glMatrixMode(%GL_MODELVIEW)
                          
                          glClearColor(0.1, 0.1, .2, 0) '<--- Set background screen color
                          glClear(ClearClr)
                          
                          
                          END SUB
                          
                          '----------------------------------------------------------------
                          '----------------------------------------------------------------
                          
                          SUB CloseOpenGL(BYVAL OglRc AS DWORD, BYVAL GfxDc AS DWORD, BYVAL GfxHndl AS DWORD)
                          
                          wglMakeCurrent(0, 0)
                          wglDeleteContext(OglRc)
                          ReleaseDc(GfxHndl,GfxDc)
                          
                          END SUB
                          
                          '----------------------------------------------------------------
                          '----------------------------------------------------------------
                          
                          SUB GetGfxWinParams(BYVAL Hndl AS DWORD, GfxHndl AS DWORD, _
                                              GfxDc AS DWORD, Wide AS LONG, High AS LONG)
                          
                          LOCAL tRect AS WinRect_STRUCT
                          
                          GfxHndl = GetDlgItem(Hndl, %GFX_WIN)
                          GetClientRect(GfxHndl, tRect)
                          Wide = tRect.Brx
                          High = tRect.Bry
                          GfxDc = GetDc(GfxHndl)
                          
                          END SUB
                          
                          '-----------------------------------------------------------------
                          '-----------------------------------------------------------------
                          
                          SUB OglRenderImage(BYVAL X AS SINGLE, BYVAL Y AS SINGLE, BYVAL Z AS SINGLE, _
                                             BYVAL TransX AS SINGLE, BYVAL TransY AS SINGLE, _
                                             BYVAL TransZ AS SINGLE, tColor() AS RGB_STRUCT, _
                                             tPnts() AS Vertex_STRUCT)
                          
                          '==================================================================
                          ' This draws the picture.
                          '
                          ' When a spot light is used, Ogl does all the calculations for you,
                          ' including those for ambient light.
                          '
                          '==================================================================
                          
                          LOCAL UbPnts  AS WORD
                          LOCAL Idx     AS WORD
                          
                          UbPnts = UBOUND(tPnts)
                          
                          glPushMatrix
                          '
                          glRotateF(X, 0, 0.001!, 0)
                          glRotateF(Y, 0.001!, 0, 0)
                          glRotateF(Azi, 0, 0, .001)
                          
                          glTranslateF(TransX!, TransY!, TransZ!)
                          
                          glBegin(%GL_QUADS)
                          '
                            FOR I = 1 TO UbPnts
                              IF tPnts(I).W = 1.0! THEN
                                Idx = tPnts(I).X
                                glColor3Ub(tColor(Idx).R, tColor(Idx).G, tColor(Idx).B)
                                ITERATE FOR
                              END IF
                              glVertex3F(tPnts(I).X, tPnts(I).Y, tPnts(I).Z)
                            NEXT I
                          glEnd
                          '
                          glPopMatrix
                          
                          END SUB
                          
                          '-------------------------------------------------------------------
                          '-------------------------------------------------------------------
                          
                          FUNCTION FnGfx_Ctl_CB(BYVAL Hndl AS LONG, BYVAL Msg AS LONG, _
                                                BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                          
                          LOCAL WordPtr AS WORD POINTER
                          
                          SELECT CASE AS LONG Msg
                            WordPtr = VARPTR(lParam)
                            CASE %WM_ERASEBKGND
                          
                            CASE %WM_LBUTTONDOWN
                              tMouse.Mx = @WordPtr[0]
                              tMouse.My = @WordPtr[1]
                              tMouse.LbDown = 1
                              tMouse.LbUp = 0
                              tMouse.RbDown = 0
                              EXIT FUNCTION
                          
                            CASE %WM_LBUTTONUP
                              tMouse.Mx = @WordPtr[0]
                              tMouse.My = @WordPtr[1]
                              tMouse.LbDown = 0
                              tMouse.LbUp = 1
                              tMouse.RbDown = 0
                              tMouse.RbUp = 0
                              EXIT FUNCTION
                          
                            CASE %WM_RBUTTONDOWN
                              tMouse.Mx = @WordPtr[0]
                              tMouse.My = @WordPtr[1]
                              tMouse.LbDown = 0
                              tMouse.LbUp = 0
                              tMouse.RbDown = 1
                              tMouse.RbUp = 0
                              EXIT FUNCTION
                          
                            CASE %WM_RBUTTONUP
                              tMouse.Mx = @WordPtr[0]
                              tMouse.My = @WordPtr[1]
                              tMouse.LbDown = 0
                              tMouse.LbUp = 0
                              tMouse.RbDown = 0
                              tMouse.RbUp = 1
                              EXIT FUNCTION
                          
                            CASE %WM_MOUSEMOVE
                              IF (wParam AND %MK_LBUTTON) = %MK_LBUTTON THEN
                                tMouse.Mx = @WordPtr[0]
                                tMouse.My = @WordPtr[1]
                                tMouse.LbDown = 1
                                tMouse.LbUp = 0
                                tMouse.RbDown = 0
                                tMouse.RbUp = 0
                                EXIT FUNCTION
                              END IF
                          
                          END SELECT
                          FUNCTION = DefWindowProc(Hndl, Msg, wParam, lParam)
                          END FUNCTION
                          
                          '-----------------------------------------------------------
                          '-----------------------------------------------------------
                          
                          SUB RegWindow(Nam AS ASCIIZ, BYVAL Styl AS DWORD, BYVAL Code_Ptr AS DWORD, _
                                                   BYVAL Inst AS DWORD, BYVAL BkBrush AS DWORD, RegOk AS BYTE)
                          
                          LOCAL tWindow AS WNDCLASSEX
                          
                          tWindow.cbSize        = SIZEOF(tWindow)
                          tWindow.style         = Styl
                          tWindow.lpfnWndProc   = Code_Ptr
                          tWindow.cbClsExtra    = 0
                          tWindow.cbWndExtra    = 32
                          tWindow.hInstance     = Inst
                          tWindow.hIcon         = %NULL
                          tWindow.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                          
                          IF BkBrush = 0 THEN
                            tWindow.hbrBackground = 0
                          ELSE
                            tWindow.hbrBackground = GetStockObject(BkBrush)
                          END IF
                          
                          tWindow.lpszMenuName  = %NULL
                          tWindow.lpszClassName = VARPTR(Nam$)
                          tWindow.hIconSm       = %NULL
                          
                          Styl = RegisterClassEx(tWindow)
                          
                          IF Styl THEN RegOk = 1
                          
                          END SUB
                          
                          '-----------------------------------------------------------------------------
                          '-----------------------------------------------------------------------------
                          
                          SUB Obj_Data(Obj_Points() AS Vertex_STRUCT)
                          
                          LOCAL Dcount AS WORD
                          
                          '=======================================================
                          '                      Color Data
                          '-------------------------------------------------------
                          ' The first number is the index to the color array
                          ' The second number is a flag to indicate that color
                          ' should be used at this vertex
                          '-------------------------------------------------------
                          
                          DATA   1,   0,  0, 1
                          
                          '========================================================
                          '                      Vector Data
                          '--------------------------------------------------------
                          ' The negative number indicates that a unit normal
                          ' vector is calculated for this polygon.  The value
                          ' of the negative number is the index to the unit
                          ' normal array
                          '--------------------------------------------------------
                          ' front
                          DATA -15,  15,  15, -1
                          DATA   7,   0,   0,  1
                          DATA  15,  15,  15,  0
                          DATA  15, -15,  15,  0
                          DATA   8,   0,   0,  1
                          DATA -15, -15,  15,  0
                          
                          DATA   2,   0,   0,  1
                          ' right
                          DATA  15,  15,  15, -2
                          DATA   9,   0,   0,  1
                          DATA  15, -15,  15,  0
                          DATA  15, -15, -15,  0
                          DATA  10,   0,   0,  1
                          DATA  15,  15, -15,  0
                          
                          DATA   3,   0,   0,  1
                          'left
                          DATA -15,  15,  15, -3
                          DATA -15, -15,  15,  0
                          DATA  11,   0,   0,  1
                          DATA -15, -15, -15,  0
                          DATA  12,   0,   0,  1
                          DATA -15,  15, -15,  0
                          
                          DATA   4,   0,   0,  1
                          'top
                          DATA -15,  15,  15, -4
                          DATA  13,   0,   0,  1
                          DATA  15,  15,  15,  0
                          DATA  14,   0,   0,  1
                          DATA  15,  15, -15,  0
                          DATA  15,   0,   0,  1
                          DATA -15,  15, -15,  0
                          
                          DATA   5,   0,   0,  1
                          'bottom
                          DATA -15, -15,  15, -5
                          DATA  15, -15,  15,  0
                          DATA  16,   0,   0,  1
                          DATA  15, -15, -15,  0
                          DATA -15, -15, -15,  0
                          'back
                          
                          DATA   6,   0,   0,  1
                          DATA -15,  15, -15, -6
                          DATA  15,  15, -15,  0
                          DATA  15, -15, -15,  0
                          DATA -15, -15, -15,  0
                          
                          
                          
                          Dcount = DATACOUNT
                          
                          REDIM ObJ_Points(1 TO Dcount \ 4)
                          
                          FOR I = 1 TO DCount STEP 4
                            INCR J
                            Obj_Points(J).X = VAL(READ$(I))
                            Obj_Points(J).Y = VAL(READ$(I + 1))
                            Obj_Points(J).Z = VAL(READ$(I + 2))
                            Obj_Points(J).W = VAL(READ$(I + 3))
                          NEXT I
                          END SUB
                          
                          '-----------------------------------------------
                          '-----------------------------------------------
                          
                          SUB Color_Data(Kolor() AS RGB_STRUCT)
                          
                          LOCAL Dcount AS WORD
                          
                          REDIM Kolor(1 TO 16)
                          
                          FOR I = 1 TO 16
                            Kolor(I).R = RND(0, 255)
                            Kolor(I).G = RND(0, 255)
                            Kolor(I).B = RND(0, 255)
                          NEXT I
                          
                          END SUB
                          
                          '--------------------------------------------------
                          '--------------------------------------------------
                          
                          SUB RenderStars(tStars() AS Vertex_STRUCT)
                          
                          '===============================================
                          ' This routine draws the background stars (white points).
                          ' In order for them to show up as white lighting has to
                          ' be disabled and restored when finished. That's what
                          ' glPushAttrib() and glPopAttrib() does.
                          '================================================
                          
                          LOCAL R AS BYTE
                          LOCAL G AS BYTE
                          LOCAL B AS BYTE
                          
                          LOCAL Zmin    AS LONG
                          LOCAL Zmax    AS LONG
                          LOCAL ZRange  AS LONG
                          
                          LOCAL ZRatio  AS SINGLE
                          
                          Zmin = -75
                          Zmax = -200
                          ZRange = Zmin + (Zmax - Zmin)
                          
                          glPushMatrix
                          
                            glPushAttrib(%GL_LIGHTING_BIT)
                            glDisable(%GL_LIGHTING)
                          
                          
                            glBegin(%GL_POINTS)
                              FOR I = 1 TO UBOUND(tStars)
                                R = 255
                                G = 255
                                B = 255
                                ZRatio! = tStars(I).Z / ZRange   ' <--- Make star intensity a function of
                                R = R * ZRatio!                  '      its "Z" position in relation then
                                G = G * ZRatio!                  '      "Z" display center, e.g. less intense
                                B = B * ZRatio!                  '      = farther away.
                                glColor3Ub(R, G, B)
                                glVertex3F(tStars(I).X, tStars(I).Y, tStars(I).Z)
                              NEXT I
                            glEnd
                          
                            glPopAttrib()
                          glPopMatrix
                          
                          END SUB
                          
                          '------------------------------------------------------
                          '------------------------------------------------------
                          
                          SUB SetSpot(BYVAL X AS SINGLE, BYVAL Y AS SINGLE, BYVAL Azi AS SINGLE, _
                                      LightPosn() AS SINGLE, LiteDir() AS SINGLE)
                          
                          '===============================================================
                          ' To set the light position we have to save the model view matrix,
                          ' save the light model matrix, disable lighting, move to the light
                          ' position, then restore the matrices
                          '===============================================================
                          
                          glPushMatrix                ' <--- Save model view matrix
                          
                          IF tFlags.Sphere THEN
                            glRotateF(10, 0, 1, 0)    ' <--- Rotate the light position
                            glRotateF(60, 1, 0, 1)    '      and direction to specified
                            glRotateF(30!, 0, 0, 1)   '      position
                          ELSE
                            glRotateF(X!, 0, 1, 0)
                            glRotateF(Y!, 1, 0, 1)
                            glRotateF(Azi!, 0, 0, 1)
                          END IF
                          
                          glLightFV(%GL_LIGHT0, %GL_POSITION, LightPosn(0))
                          glLightFV(%GL_LIGHT0, %GL_SPOT_DIRECTION, LiteDir(0))
                          
                          glColor3Ub(255, 0, 0)
                          
                          glTranslateF(LightPosn(0), LightPosn(1), LightPosn(2)) ' <--- Move to new postion
                          
                          AuxSolidCone(10!, 16.0!)
                          
                          glPushAttrib(%GL_LIGHTING_BIT)    ' <--- Save light matrix
                          
                          glDisable(%GL_LIGHTING)           ' <--- Disable lighting
                          
                          glColor3Ub(255, 255, 0)
                          
                          AuxSolidSphere(6.0!)
                          
                          glPopAttrib()                     ' <--- Restore light matrix
                          
                          glPopMatrix                       ' <--- Resore model view matrix
                          
                          END SUB
                          
                          '--------------------------------------------------------
                          '--------------------------------------------------------
                          
                          SUB RenderSphere(BYVAL X AS SINGLE, BYVAL Y AS SINGLE, BYVAL Z AS SINGLE)
                          
                          glPushMatrix
                          
                            glColor3Ub(0, 175, 255)
                          
                            IF tFlags.Sphere THEN
                              glRotateF(Y!, 0, .001!, 0)
                              glRotateF(X!, .001!, 0, 0)
                              glRotateF(Z!, 0, 0, .001!)
                            END IF
                          
                            AuxSolidSphere(50)
                          
                          glPopMatrix
                          
                          END SUB
                          
                          '---------------------------------------------------------
                          '---------------------------------------------------------
                          
                          SUB Position_Stars(tStars() AS Vertex_STRUCT)
                          
                          FOR I = 1 TO 100
                            tStars(I).X = RND(-200, 200)
                            tStars(I).Y = RND(-200, 200)
                            tStars(I).Z = RND(-75, -200)
                          NEXT I
                          
                          END SUB
                          
                          SUB AddLite(Ambient() AS SINGLE, Diffusion() AS SINGLE, MatReflect() AS SINGLE, _
                                      SpecReflect() AS SINGLE, LightPosn() AS SINGLE, LiteDir() AS SINGLE)
                          
                          Ambient!(0) = .35
                          Ambient!(1) = .25
                          Ambient!(2) = .20
                          Ambient!(3) = 0
                          
                          LightPosn!(0) = 0  ' <--- Light postion
                          LightPosn!(1) = 0
                          
                          '=========================================
                          ' If this value is negative the third
                          ' element in the light direction (LiteDir())
                          ' must be positive
                          '-----------------------------------------
                          
                          LightPosn!(2) = -200
                          '=========================================
                          
                          '=========================================
                          ' Light attenuation increases as this value
                          ' increases, i. e., as this value approches
                          ' one or greater than one, the spot on the
                          ' sphere becomes smaller and there is less
                          ' scatter.
                          '-----------------------------------------
                          '
                          LightPosn!(3) = .10
                          '
                          '==========================================
                          
                          LiteDir!(0) = 0    ' <--- Light direction
                          LiteDir!(1) = 0
                          
                          '==========================================
                          ' If this element in the light direction is
                          ' positive then the third element in the
                          ' light postion (LightPosn()) must be negative
                          '------------------------------------------
                          '
                          LiteDir!(2) = 1
                          '
                          '==========================================
                          
                          glEnable(%GL_DEPTH_TEST)
                          glEnable(%GL_LIGHTING)
                          glLightModelFV(%GL_LIGHT_MODEL_AMBIENT, Ambient!(0))
                          glLightFV(%GL_LIGHT0, %GL_DIFFUSE, Ambient!(0))
                          glLightFV(%GL_LIGHT0, %GL_SPECULAR, MatReflect!(0))
                          glLightFV(%GL_LIGHT0, %GL_POSITION, LightPosn!(0))
                          
                          '=================================================
                          ' Small spot light; however, this is partially
                          ' over-ridden by the 4th parameter of the light
                          ' postion parameters.
                          '-------------------------------------------------
                          '
                          glLightF(%GL_LIGHT0, %GL_SPOT_CUTOFF, 10)
                          '
                          '==================================================
                          
                          glLightF(%GL_LIGHT0, %GL_SPOT_EXPONENT, 128) '<--- Bright Light
                          glEnable(%GL_LIGHT0)
                          glEnable(%GL_COLOR_MATERIAL)
                          glColorMaterial(%GL_FRONT, %GL_AMBIENT_AND_DIFFUSE)
                          glMaterialFV(%GL_FRONT, %GL_SPECULAR, SpecReflect!(0))
                          
                          '=================================================
                          ' Governs shininess of objects and, as the number
                          ' approches 128, the size of the spot on the sphere.
                          '-------------------------------------------------
                          '
                          glMaterialI(%GL_FRONT, %GL_SHININESS, 5)     '<--- Very shinny
                          '                                            '     Large, diffuse spot
                          '================================================
                          
                          glLightFV(%GL_LIGHT0, %GL_SPOT_DIRECTION, LiteDir!(0))
                          
                          END SUB
                          PS: The background color is not black. It's a deep purple. You can change this by using glClearColor() with the appropriate arguments.

                          PSS: The cube is supposed to be a solid object. I just noticed that the winding for the top and bottom of the cube is counter-clockwise while the winding for the front, back and sides is clockwise. Therefore, if you add glEnable(%GL_CULL_FACES) in SUB AddLite() the top and bottom is erased when they are in view. Just another reason to insure that, when creating an object, the winding is consistent.
                          Last edited by Walt Decker; 16 Jul 2010, 10:52 AM. Reason: Error about negatives, Comment about cube
                          Walt Decker

                          Comment


                          • #14
                            Pixel Formats

                            I was curious about pixel formats. Wondered how many formats there are on my machine (8-year-old custom built job running XP PRO SP2) and if various controls supported all the formats. I found that on my machine there are 42 formats. Each of the three controls I tested (label control, graphic control, and custom control) support all of the formats. All of the formats support OpenGL.

                            The following code lists all the formats for each control (since they are the same, the listboxes are redundant). At the bottom the text box lists the dwFlags parameters. In the OpenGL environment, this might come in handy to choose the best pixel format for your application.

                            How this can be of help with anything other than OpenGL, I have no idea, but I'm sure someone can use it for something.

                            Code:
                            #PBFORMS CREATED V1.51
                            #COMPILE EXE
                            
                            DEFLNG A - Z
                            '------------------------------------------------------------------------------
                            '   ** Includes **
                            '------------------------------------------------------------------------------
                            #PBFORMS BEGIN INCLUDES
                            #IF NOT %DEF(%WINAPI)
                              #INCLUDE "WIN32API.INC"
                            #ENDIF
                            #IF NOT %DEF(%COMMCTRL_INC)
                              #INCLUDE "COMMCTRL.INC"
                            #ENDIF
                            #INCLUDE "PBForms.INC"
                            #PBFORMS END INCLUDES
                            '------------------------------------------------------------------------------
                            
                            '------------------------------------------------------------------------------
                            '   ** Constants **
                            '------------------------------------------------------------------------------
                            #PBFORMS BEGIN CONSTANTS
                            
                            TYPE Single2_STRUCT
                              Mx      AS SINGLE
                              My      AS SINGLE
                            END TYPE
                            
                            TYPE Mouse_Btn_STRUCT
                              LbDown  AS BIT * 1 IN BYTE
                              LbUp    AS BIT * 1
                              RbDown  AS BIT * 1
                              RbUp    AS BIT * 1
                            END TYPE
                            
                            TYPE Mouse_STRUCT
                              Single2_STRUCT
                              Mouse_Btn_STRUCT
                            END TYPE
                            
                            %DLG_DIALOG1         =  101
                            %IDC_SYSTREEVIEW32_1 = 1
                            %GFX_CTRL            = 2
                            %LBL_LABEL1          = 3
                            
                            %LBL_GFX             = 5
                            %LBL_LABEL           = 6
                            %LBL_CUSTOM          = 7
                            
                            %LBX_LISTBOX1        = 10
                            %LBX_LISTBOX2        = 11
                            %LBX_LISTBOX3        = 12
                            %TXBX_TEXTBOX1       = 13
                            
                            %GFX_WIN             = 20
                            
                            %DLG_MESS            = %WM_USER + 500
                            
                            %GFX_CTL             = %WM_USER + 501
                            %LBL_CTL             = %WM_USER + 502
                            %CST_CTL             = %WM_USER + 503
                            
                            'GLOBAL tFlags AS OglFlag_STRUCT
                            GLOBAL tMouse AS Mouse_STRUCT
                            
                            #PBFORMS END CONSTANTS
                            '------------------------------------------------------------------------------
                            
                            '------------------------------------------------------------------------------
                            '   ** Declarations **
                            '------------------------------------------------------------------------------
                            DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
                            DECLARE FUNCTION SampleTreeViewInsertItem(BYVAL hTree AS DWORD, BYVAL hParent _
                              AS DWORD, sItem AS STRING) AS LONG
                            DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                            #PBFORMS DECLARATIONS
                            '------------------------------------------------------------------------------
                            
                            '------------------------------------------------------------------------------
                            '   ** Main Application Entry Point **
                            '------------------------------------------------------------------------------
                            FUNCTION PBMAIN()
                              PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR _
                                %ICC_INTERNET_CLASSES)
                            
                              ShowDIALOG1 %HWND_DESKTOP
                            END FUNCTION
                            '------------------------------------------------------------------------------
                            
                            '------------------------------------------------------------------------------
                            '   ** CallBacks **
                            '------------------------------------------------------------------------------
                            CALLBACK FUNCTION ShowDIALOG1Proc()
                            
                            LOCAL DlgHnd AS DWORD
                            LOCAL Num1   AS WORD
                            
                            LOCAL tPixFmt   AS PIXELFORMATDESCRIPTOR
                            LOCAL tNmHdrPtr AS NMHDR POINTER
                            
                            STATIC DlgLstHndl AS DWORD
                            
                            DlgHnd = CBHNDL
                            
                            SELECT CASE AS LONG CBMSG
                              CASE %WM_INITDIALOG
                                ' Initialization handler
                              Inst = GetWindowLong(DLgHnd, %GWL_HINSTANCE)
                              Styl = %CS_HREDRAW OR %CS_VREDRAW OR %CS_OWNDC OR %CS_GLOBALCLASS
                            
                              CALL RegWindow("OglCtl" + $NUL, Styl, CODEPTR(FnGfx_Ctl_CB), Inst, %NULL_BRUSH, 0)
                            
                              Styl = %WS_VISIBLE OR %WS_TABSTOP OR %WS_CHILD OR %DS_CONTROL OR %WS_GROUP
                            
                              CONTROL ADD "OglCtl", DlgHnd, %GFX_WIN, "", 165, 5, 75, 65, Styl, %WS_EX_CLIENTEDGE
                              GRAPHIC ATTACH DlgHnd, %GFX_CTRL
                              GRAPHIC PRINT "GRAPHIC CONTROL"
                              GRAPHIC DETACH
                              DIALOG POST DlgHnd, %DLG_MESS, 0, 0
                              DIALOG POST DlgHnd, %DLG_MESS, 1, 0
                              CASE %WM_NCACTIVATE
                                STATIC hWndSaveFocus AS DWORD
                                IF ISFALSE CBWPARAM THEN
                                  ' Save control focus
                                  hWndSaveFocus = GetFocus()
                                ELSEIF hWndSaveFocus THEN
                                  ' Restore control focus
                                  SetFocus(hWndSaveFocus)
                                  hWndSaveFocus = 0
                                END IF
                            
                              CASE %WM_COMMAND
                                ' Process control notifications
                                IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = %STN_CLICKED THEN
                                SELECT CASE AS LONG CBCTL
                                  CASE %IDC_SYSTREEVIEW32_1
                            
                                  CASE %GFX_CTRL
                            
                                  CASE %LBL_LABEL1
                            
                                END SELECT
                                END IF
                              CASE %WM_NOTIFY
                                tNmHdrPtr = CB.NMHDR
                            
                                  ' What type of notification message is this?
                                  SELECT CASE AS LONG @tNmHdrPtr.code
                                    CASE %TVN_SELCHANGED
                                      TREEVIEW GET SELECT DlgHnd, %IDC_SYSTREEVIEW32_1 TO  SelHndl
                                      TREEVIEW GET PARENT DlgHnd, %IDC_SYSTREEVIEW32_1, SelHndl TO ParHndl
                                      IF ParHndl = 0 THEN EXIT SELECT
                            '          TREEVIEW GET TEXT DlgHnd, %IDC_SYSTREEVIEW32_1, ParHndl TO ParTxt$
                                      TREEVIEW GET TEXT DlgHnd, %IDC_SYSTREEVIEW32_1, SelHndl TO SelTxt$
                                      Sp = INSTR(-1, SelTxt$, " ")
                                      FmtNum = VAL(MID$(SelTxt$, Sp))
                            
                                      IF INSTR(UCASE$(SelTxt$), "GRAPHIC") THEN
                                        CALL GetNumFormats(DlgHnd, %GFX_CTRL, FmtNum, tPixFmt, 0)
                                        Txt$ = "GRAPHIC CONTROL" + $CRLF + "Format: " + STR$(FmtNum)
                                        CONTROL SET TEXT DlgLstHndl, %LBL_GFX, Txt$
                                        CALL FillList(DlgLstHndl, %LBX_LISTBOX1, tPixFmt)
                                      END IF
                                      IF INSTR(UCASE$(SelTxt$), "LABEL") THEN
                                        CALL GetNumFormats(DlgHnd, %LBL_LABEL1, FmtNum, tPixFmt, 0)
                                        Txt$ = "LABEL CONTROL" + $CRLF + "Format: " + STR$(FmtNum)
                                        CONTROL SET TEXT DlgLstHndl, %LBL_LABEL, Txt$
                                        CALL FillList(DlgLstHndl, %LBX_LISTBOX2, tPixFmt)
                                      END IF
                                      IF INSTR(UCASE$(SelTxt$), "CUSTOM") THEN
                                        CALL GetNumFormats(DlgHnd, %GFX_WIN, FmtNum, tPixFmt, 0)
                                        Txt$ = "CUSTOM CONTROL" + $CRLF + "Format: " + STR$(FmtNum)
                                        CONTROL SET TEXT DlgLstHndl, %LBL_CUSTOM, Txt$
                                        CALL FillList(DlgLstHndl, %LBX_LISTBOX3, tPixFmt)
                                      END IF
                                  END SELECT
                            
                              CASE %DLG_MESS
                                SELECT CASE CBWPARAM
                                  CASE 0
                                    CALL GetNumFormats(DlgHnd, %GFX_CTRL, 1, tPixFmt, Num1)
                                    CALL SetTreeView(DlgHnd, %IDC_SYSTREEVIEW32_1, _
                                                     "DDT Graphic Control", "Graphic Control Pixel Format #", _
                                                      Num1)
                                    CALL GetNumFormats(DlgHnd, %LBL_LABEL1, 1, tPixFmt, Num1)
                                    CALL SetTreeView(DlgHnd, %IDC_SYSTREEVIEW32_1, _
                                                     "Label Control", "Label Control Pixel Format #", _
                                                     Num1)
                                    CALL GetNumFormats(DlgHnd, %GFX_WIN, 1, tPixFmt, Num1)
                                    CALL SetTreeView(DlgHnd, %IDC_SYSTREEVIEW32_1, _
                                                     "Custom Control", "Custom Control Pixel Format #", _
                                                     Num1)
                                  CASE 1
                                    CALL ShowDIALOG2(DlgHnd)
                            
                                  CASE 2
                                    DlgLstHndl = CBLPARAM
                                END SELECT
                            END SELECT
                            
                            END FUNCTION
                            
                            '---------------------------------------------------------------------
                            '---------------------------------------------------------------------
                            
                            FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                              LOCAL lRslt AS LONG
                            
                            #PBFORMS BEGIN DIALOG %DLG_DIALOG1->->
                              LOCAL hDlg  AS DWORD
                            
                              DIALOG NEW hParent, "Dialog1", 182, 86, 267, 176, %WS_POPUP OR %WS_BORDER _
                                OR %WS_DLGFRAME OR %WS_CAPTION OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR _
                                %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
                                %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                %WS_EX_RIGHTSCROLLBAR, TO hDlg
                              CONTROL ADD "SysTreeView32", hDlg, %IDC_SYSTREEVIEW32_1, "SysTreeView32_1", _
                                5, 5, 70, 160, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _
                                %TVS_HASBUTTONS OR %TVS_HASLINES OR %TVS_LINESATROOT OR _
                                %TVS_SHOWSELALWAYS OR %TVS_FULLROWSELECT, %WS_EX_LEFT OR _
                                %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
                              CONTROL ADD GRAPHIC, hDlg, %GFX_CTRL, "", 80, 5, 75, 65, %WS_CHILD OR _
                                %WS_VISIBLE OR %WS_TABSTOP OR %SS_SUNKEN OR %SS_NOTIFY
                              CONTROL ADD LABEL,   hDlg, %LBL_LABEL1, "LABEL CONTROL", 80, 95, _
                                75, 70, %WS_CHILD OR %WS_VISIBLE OR %SS_CENTER OR %SS_NOTIFY OR _
                                %SS_SUNKEN, %WS_EX_LEFT OR %WS_EX_LTRREADING
                            #PBFORMS END DIALOG
                            
                              DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                            
                            #PBFORMS BEGIN CLEANUP %DLG_DIALOG1
                            #PBFORMS END CLEANUP
                            
                              FUNCTION = lRslt
                            END FUNCTION
                            
                            '-----------------------------------------------------------
                            '-----------------------------------------------------------
                            
                            SUB RegWindow(Nam AS ASCIIZ, BYVAL Styl AS DWORD, BYVAL Code_Ptr AS DWORD, _
                                                     BYVAL Inst AS DWORD, BYVAL BkBrush AS DWORD, RegOk AS BYTE)
                            
                            LOCAL tWindow AS WNDCLASSEX
                            
                            tWindow.cbSize        = SIZEOF(tWindow)
                            tWindow.style         = Styl
                            tWindow.lpfnWndProc   = Code_Ptr
                            tWindow.cbClsExtra    = 0
                            tWindow.cbWndExtra    = 32
                            tWindow.hInstance     = Inst
                            tWindow.hIcon         = %NULL
                            tWindow.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                            
                            IF BkBrush = 0 THEN
                              tWindow.hbrBackground = 0
                            ELSE
                              tWindow.hbrBackground = GetStockObject(BkBrush)
                            END IF
                            
                            tWindow.lpszMenuName  = %NULL
                            tWindow.lpszClassName = VARPTR(Nam$)
                            tWindow.hIconSm       = %NULL
                            
                            Styl = RegisterClassEx(tWindow)
                            
                            IF Styl THEN RegOk = 1
                            
                            END SUB
                            
                            '----------------------------------------------------
                            '----------------------------------------------------
                            
                            SUB MakeWindow(BYVAL StyleX AS DWORD, WinClass AS ASCIIZ, Title AS ASCIIZ, _
                                           BYVAL Styl AS DWORD, BYVAL X1 AS DWORD, BYVAL Y1 AS DWORD, _
                                           BYVAL X2 AS DWORD, BYVAL Y2 AS DWORD, BYVAL Owner AS DWORD, _
                                           BYVAL CtlNum AS DWORD, BYVAL Inst AS DWORD, Hndl AS DWORD)
                            
                            Hndl = CreateWindowEx(StyleX, _       ' extended Window style
                                                  WinClass$, _    ' window class name
                                                  Title$, _       ' window caption
                                                  Styl, _         ' window style
                                                  X1, _           ' initial x position
                                                  Y1, _           ' initial y position
                                                  X2, _           ' initial x size
                                                  Y2, _           ' initial y size
                                                  Owner, _        ' parent window handle
                                                  BYVAL CtlNum, _ ' window menu handle
                                                  Inst, _         ' program instance handle
                                                  BYVAL %NULL)    ' creation parameters
                            
                            END SUB
                            
                            '---------------------------------------------------------------
                            '---------------------------------------------------------------
                            
                            FUNCTION FnGfx_Ctl_CB(BYVAL Hndl AS LONG, BYVAL Msg AS LONG, _
                                                  BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                            
                            LOCAL DlgHndl   AS DWORD
                            LOCAL CtlId     AS DWORD
                            
                            STATIC TickCount AS DWORD
                            
                            LOCAL ParamW  AS LONG
                            LOCAL ParamL  AS LONG
                            
                            LOCAL BmpStr  AS STRING
                            
                            LOCAL CurDrw  AS BYTE
                            LOCAL CurLvl  AS BYTE
                            
                            LOCAL WordPtr AS WORD POINTER
                            LOCAL tPaint AS PAINTSTRUCT
                            'CurDrw = tFlags.CurDrw
                            'CurLvl = tInfo(CurDrw).CurLvl
                            'DlgHndl = tInfo(CurDrw).DlgHnd
                            'CtlId = tInfo(CurDrw).GfxId
                            'GfxHndl = tInfo(CurDrw).GfxHnd
                            
                            SELECT CASE AS LONG Msg
                              WordPtr = VARPTR(lParam)
                              CASE %WM_ERASEBKGND
                            '    ParamW = GetDlgCtrlId(Hndl) - %GFX
                            '    CALL Refresh(wParam, Hndl, ParamW)
                            '    FUNCTION = 0
                            '    EXIT FUNCTION
                            
                              CASE %WM_LBUTTONDOWN
                                tMouse.Mx = @WordPtr[0]
                                tMouse.My = @WordPtr[1]
                                tMouse.LbDown = 1
                                tMouse.LbUp = 0
                                tMouse.RbDown = 0
                            '    FUNCTION = 0
                            '    EXIT FUNCTION
                            
                              CASE %WM_LBUTTONUP
                                tMouse.Mx = @WordPtr[0]
                                tMouse.My = @WordPtr[1]
                                tMouse.LbDown = 0
                                tMouse.LbUp = 1
                                tMouse.RbDown = 0
                                tMouse.RbUp = 0
                            '    FUNCTION = 0
                            '    EXIT FUNCTION
                            
                              CASE %WM_RBUTTONDOWN
                                tMouse.Mx = @WordPtr[0]
                                tMouse.My = @WordPtr[1]
                                tMouse.LbDown = 0
                                tMouse.LbUp = 0
                                tMouse.RbDown = 1
                                tMouse.RbUp = 0
                            '    FUNCTION = 0
                            '    EXIT FUNCTION
                            
                              CASE %WM_RBUTTONUP
                                tMouse.Mx = @WordPtr[0]
                                tMouse.My = @WordPtr[1]
                                tMouse.LbDown = 0
                                tMouse.LbUp = 0
                                tMouse.RbDown = 0
                                tMouse.RbUp = 1
                            '    function = 0
                            '    exit function
                            
                              CASE %WM_MOUSEMOVE
                                IF (wParam AND %MK_LBUTTON) = %MK_LBUTTON THEN
                                  tMouse.Mx = @WordPtr[0]
                                  tMouse.My = @WordPtr[1]
                                  tMouse.LbDown = 1
                                  tMouse.LbUp = 0
                                  tMouse.RbDown = 0
                                  tMouse.RbUp = 0
                            '      function = 0
                            '      exit function
                                END IF
                              CASE %WM_PAINT
                                ParHndl = GetParent(Hndl)
                                CONTROL GET CLIENT ParHndl, %GFX_WIN TO X, Y
                                DIALOG UNITS ParHndl, X, Y TO PIXELS X, Y
                                GRAPHIC BITMAP NEW X, Y TO BmpHndl
                                GRAPHIC ATTACH BmpHndl, 0
                                GRAPHIC CLEAR %RGB_LIGHTGRAY
                                GRAPHIC PRINT "CUSTOM CONTROL"
                                GRAPHIC GET DC TO BmpDC
                            
                                CtlDc = BeginPaint(Hndl, tPaint)
                                  Bitblt(CtlDc, 0, 0, X, Y, BmpDc, 0, 0, %SRCCOPY)
                                EndPaint(Hndl, tPaint)
                                GRAPHIC BITMAP END
                                EXIT FUNCTION
                            END SELECT
                            FUNCTION = DefWindowProc(Hndl, Msg, wParam, lParam)
                            END FUNCTION
                            
                            '-----------------------------------------------------------
                            '-----------------------------------------------------------
                            
                            SUB GetNumFormats(BYVAL DlgHnd AS DWORD, BYVAL CtlId AS DWORD, BYVAL FmtNum AS WORD, _
                                              tPixFmt AS PIXELFORMATDESCRIPTOR, Num1 AS WORD)
                            
                            LOCAL CtlHndl AS DWORD
                            LOCAL CtlDc   AS DWORD
                            
                            CtlHndl = GetDlgItem(DlgHnd, CtlId)
                            CtlDc = GetDc(CtlHndl)
                            Num1 = DescribePixelFormat(CtlDc, FmtNum, SIZEOF(tPixFmt), tPixFmt)
                            ReleaseDc(CtlHndl, CtlDc)
                            
                            END SUB
                            
                            '-------------------------------------------------------------
                            '-------------------------------------------------------------
                            
                            SUB SetTreeView(BYVAL DlgHnd AS DWORD, BYVAL TreeId AS DWORD, _
                                            ParentStr AS STRING, ChildStr AS STRING, BYVAL NumNodes AS WORD)
                            
                            LOCAL TreeRoot AS DWORD
                            LOCAL TvHndl  AS DWORD
                            
                            TvHndl = GetDlgItem(DlgHnd, TreeId)
                            
                            TreeRoot = InsertTvItem(TvHndl, %NULL, ParentStr$)
                            
                            FOR I = 1 TO NumNodes
                              InsertTvItem(TvHndl, TreeRoot, USING$(ChildStr$, I))
                            NEXT I
                            
                            END SUB
                            
                            '---------------------------------------------------------
                            '---------------------------------------------------------
                            FUNCTION InsertTvItem(BYVAL TreeHndl AS DWORD, BYVAL ItemNum AS DWORD, ItemTxt AS STRING )
                            
                              LOCAL tTVItem   AS TV_ITEM
                              LOCAL tTVInsert AS TV_INSERTSTRUCT
                            
                              IF hParent THEN
                                tTVItem.mask      = %TVIF_CHILDREN OR %TVIF_HANDLE
                                tTVItem.hItem     = ItemNum
                                tTVItem.cchildren = 1
                                TreeView_SetItem(TreeHndl, tTVItem)
                              END IF
                            
                              tTVInsert.hParent              = ItemNum
                              tTVInsert.Item.Item.mask       = %TVIF_TEXT
                              tTVInsert.Item.Item.pszText    = STRPTR(ItemTxt$)
                              tTVInsert.Item.Item.cchTextMax = LEN(ItemTxt$)
                            
                              FUNCTION = TreeView_InsertItem(TreeHndl, tTVInsert)
                            END FUNCTION
                            
                            '------------------------------------------------------------
                            '------------------------------------------------------------
                            
                            CALLBACK FUNCTION ShowDIALOG2Proc()
                            
                              SELECT CASE AS LONG CBMSG
                                CASE %WM_INITDIALOG
                                  ' Initialization handler
                            
                                CASE %WM_NCACTIVATE
                                  STATIC hWndSaveFocus AS DWORD
                                  IF ISFALSE CBWPARAM THEN
                                    ' Save control focus
                                    hWndSaveFocus = GetFocus()
                                  ELSEIF hWndSaveFocus THEN
                                    ' Restore control focus
                                    SetFocus(hWndSaveFocus)
                                    hWndSaveFocus = 0
                                  END IF
                            
                                CASE %WM_COMMAND
                                  ' Process control notifications
                                  SELECT CASE AS LONG CBCTL
                            
                                    CASE %LBX_LISTBOX1
                            
                                    CASE %LBX_LISTBOX2
                            
                                    CASE %LBX_LISTBOX3
                            
                                  END SELECT
                                CASE %GFX_CTL
                                CASE %LBL_CTL
                                CASE %CST_CTL
                            
                              END SELECT
                            END FUNCTION
                            '------------------------------------------------------------
                            '------------------------------------------------------------
                            
                            FUNCTION ShowDIALOG2(BYVAL hParent AS DWORD) AS LONG
                              LOCAL lRslt AS LONG
                            
                            #PBFORMS BEGIN DIALOG %DLG_DIALOG2->->
                              LOCAL hDlg  AS DWORD
                            
                              DIALOG NEW hParent, "Dialog2", 112, 35, 314, 250, %WS_BORDER OR _
                                %WS_DLGFRAME OR %WS_CAPTION OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR _
                                %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
                                %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                %WS_EX_RIGHTSCROLLBAR, TO hDlg
                              CONTROL ADD LABEL,   hDlg, %LBL_GFX, "GRAPHIC CONTROL", 15, 5, 75, 20, _
                                %WS_CHILD OR %WS_VISIBLE OR %SS_CENTER OR %SS_SUNKEN, %WS_EX_LEFT OR _
                                %WS_EX_LTRREADING
                              CONTROL ADD LABEL,   hDlg, %LBL_LABEL, "LABEL CONTROL", 120, 5, 75, 20, _
                                %WS_CHILD OR %WS_VISIBLE OR %SS_CENTER OR %SS_SUNKEN, %WS_EX_LEFT OR _
                                %WS_EX_LTRREADING
                              CONTROL ADD LABEL,   hDlg, %LBL_CUSTOM, "CUSTOM CONTROL", 220, 5, 75, 20, _
                                %WS_CHILD OR %WS_VISIBLE OR %SS_CENTER OR %SS_SUNKEN, %WS_EX_LEFT OR _
                                %WS_EX_LTRREADING
                              CONTROL ADD LISTBOX, hDlg, %LBX_LISTBOX1, , 5, 40, 95, 150, %WS_CHILD OR _
                                %WS_VISIBLE OR %WS_TABSTOP OR %WS_HSCROLL OR %WS_VSCROLL OR %LBS_NOTIFY, _
                                %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                %WS_EX_RIGHTSCROLLBAR
                              CONTROL ADD LISTBOX, hDlg, %LBX_LISTBOX2, , 105, 40, 105, 150, %WS_CHILD OR _
                                %WS_VISIBLE OR %WS_TABSTOP OR %WS_VSCROLL OR %LBS_NOTIFY, _
                                %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                %WS_EX_RIGHTSCROLLBAR
                              CONTROL ADD LISTBOX, hDlg, %LBX_LISTBOX3, , 215, 40, 95, 150, %WS_CHILD OR _
                                %WS_VISIBLE OR %WS_TABSTOP OR %WS_VSCROLL OR %LBS_NOTIFY, _
                                %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                %WS_EX_RIGHTSCROLLBAR
                            
                              CONTROL ADD TEXTBOX, hDlg, %TXBX_TEXTBOX1, "", 80, 200, 155, 40, _
                                %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %WS_VSCROLL OR %ES_LEFT OR _
                                %ES_MULTILINE OR %ES_AUTOVSCROLL, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR _
                                %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
                                    #PBFORMS END DIALOG
                            
                              DIALOG POST hParent, %DLG_MESS, 2, hDlg
                            '  SampleListBox  hDlg, %LBX_LISTBOX1, 30
                            '  SampleListBox  hDlg, %LBX_LISTBOX2, 30
                            '  SampleListBox  hDlg, %LBX_LISTBOX3, 30
                            
                              DIALOG SHOW MODELESS hDlg
                            
                            #PBFORMS BEGIN CLEANUP %DLG_DIALOG2
                            #PBFORMS END CLEANUP
                            
                              FUNCTION = lRslt
                            END FUNCTION
                            
                            '---------------------------------------------------------------------
                            '---------------------------------------------------------------------
                            
                            SUB FillList(BYVAL DlgLstHndl AS DWORD, BYVAL CtlId AS DWORD, _
                                         tPixFmt AS PIXELFORMATDESCRIPTOR)
                            
                            LOCAL Txt AS STRING
                            
                            LISTBOX RESET DlgLstHndl, CtlId
                            
                            Txt$ = "nSize = " + STR$(tPixFmt.nSize)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "nVersion = " + STR$(tPixFmt.nVersion)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "dwFlags = " + STR$(tPixFmt.dwFlags)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "iPixelType = " + STR$(tPixFmt.iPixelType)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cColorBits = " + STR$(tPixFmt.cColorBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cRedBits = " + STR$(tPixFmt.cRedBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cRedShift = " + STR$(tPixFmt.cRedShift)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cGreenBits = " + STR$(tPixFmt.cGreenBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cGreenShift = " + STR$(tPixFmt.cGreenShift)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cBlueBits = " + STR$(tPixFmt.cBlueBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cBlueShift = " + STR$(tPixFmt.cBlueShift)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAlphaBits = " + STR$(tPixFmt.cAlphaBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAlphaShift = " + STR$(tPixFmt.cAlphaShift)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAccumBits = " + STR$(tPixFmt.cAccumBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAccumRedBits = " + STR$(tPixFmt.cAccumRedBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAccumGreenBits = " + STR$(tPixFmt.cAccumGreenBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAccumBlueBits = " + STR$(tPixFmt.cAccumBlueBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAccumAlphaBits = " + STR$(tPixFmt.cAccumAlphaBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cDepthBits = " + STR$(tPixFmt.cDepthBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cStencilBits" + STR$(tPixFmt.cStencilBits)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "cAuxBuffers = " + STR$(tPixFmt.cAuxBuffers)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "iLayerType = " + STR$(tPixFmt.iLayerType)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "bReserved = " + STR$(tPixFmt.bReserved)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "dwLayerMask = " + STR$(tPixFmt.dwLayerMask)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "dwVisibleMask = " + STR$(tPixFmt.dwVisibleMask)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            Txt$ = "dwDamageMask = " + STR$(tPixFmt.dwDamageMask)
                            LISTBOX ADD DlgLstHndl, CtlId, Txt$
                            
                            Txt$ = "dwFlags: " + $CRLF
                            IF (tPixFmt.dwFlags AND %PFD_DRAW_TO_WINDOW) = %PFD_DRAW_TO_WINDOW THEN
                              Txt$ = Txt$ + "%PFD_DRAW_TO_WINDOW" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_DRAW_TO_BITMAP) = %PFD_DRAW_TO_BITMAP THEN
                              Txt$ = Txt$ + "%PFD_DRAW_TO_BITMAP" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_SUPPORT_GDI) = %PFD_SUPPORT_GDI THEN
                              Txt$ = Txt$ + "%PFD_SUPPORT_GDI" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_DOUBLEBUFFER) = %PFD_DOUBLEBUFFER THEN
                              Txt$ = Txt$ + "%PFD_DOUBLEBUFFER" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_SUPPORT_OPENGL) = %PFD_SUPPORT_OPENGL THEN
                              Txt$ = Txt$ + "%PFD_SUPPORT_OPENGL" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_GENERIC_ACCELERATED) = %PFD_GENERIC_ACCELERATED THEN
                              Txt$ = Txt$ + "%PFD_GENERIC_ACCELERATED" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_GENERIC_FORMAT) = %PFD_GENERIC_FORMAT THEN
                              Txt$ = Txt$ + "%PFD_GENERIC_FORMAT" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_NEED_PALETTE) = %PFD_NEED_PALETTE THEN
                              Txt$ = Txt$ + "%PFD_NEED_PALETTE" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_NEED_SYSTEM_PALETTE) = %PFD_NEED_SYSTEM_PALETTE THEN
                              Txt$ = Txt$ + "%PFD_NEED_SYSTEM_PALETTE" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_STEREO) = %PFD_STEREO THEN
                              Txt$ = Txt$ + "%PFD_STEREO" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_SWAP_LAYER_BUFFERS)  = %PFD_SWAP_LAYER_BUFFERS THEN
                              Txt$ = Txt$ + "%PFD_SWAP_LAYER_BUFFERS" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_DEPTH_DONTCARE) = %PFD_DEPTH_DONTCARE THEN
                              Txt$ = Txt$ + "%PFD_DEPTH_DONTCARE" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_STEREO_DONTCARE) = %PFD_STEREO_DONTCARE THEN
                              Txt$ = Txt$ + "%PFD_STEREO_DONTCARE" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_SWAP_COPY) = %PFD_SWAP_COPY THEN
                              Txt$ = Txt$ + "%PFD_SWAP_COPY" + $CRLF
                            END IF
                            
                            IF (tPixFmt.dwFlags AND %PFD_SWAP_EXCHANGE) = %PFD_SWAP_EXCHANGE THEN
                              Txt$ = Txt$ + "%PFD_SWAP_EXCHANGE" + $CRLF
                            END IF
                            
                            CONTROL SET TEXT DlgLstHndl, %TXBX_TEXTBOX1, Txt$
                            '
                            
                            END SUB
                            
                            
                            '----------------------------------------------------
                            '----------------------------------------------------
                            Walt Decker

                            Comment

                            Working...
                            X