; ------------------------------------------------------
; OpenGL framework
; Copyright (c) 2005-2016, Franck Charlet
; All rights reserved.
; ------------------------------------------------------

                        .486
                        .model  flat,stdcall
                        option  casemap:none

; ------------------------------------------------------
; Includes
                        include windows.inc
                        include kernel32.inc
                        include user32.inc
                        include gdi32.inc
                        include ole32.inc
                        include oleaut32.inc

                        include ..\Include\gl.inc
                        include ..\Include\glext.inc
                        include ..\Include\glati.inc
                        include ..\Include\glxati.inc
                        include ..\Include\glu.inc
                        include ..\Include\wingdi.inc
                        include ..\Include\wglati.inc
                        include ..\Include\wglext.inc
                        include ..\Include\msvcrt.inc
                        include ..\Include\dinput.inc
                        include ..\Include\glm.inc
                        include ..\Include\Quaternions.inc
                        include ..\Include\IPicture.inc
DIRECTSOUND_VERSION     equ     00900h
                        include ..\Include\dsound.inc
                        include Macros.asm

                        includelib kernel32.lib
                        includelib user32.lib
                        includelib gdi32.lib
                        includelib opengl32.lib
                        includelib glu32.lib
                        includelib dinput.lib
                        includelib ole32.lib
                        includelib oleaut32.lib
                        includelib dsound.lib

                        includelib ..\Lib\msvcrt.lib
                        includelib ..\Lib\dxguid.lib
                        includelib ..\Lib\dinput8.lib
                        includelib ..\Lib\glm.lib
                        includelib ..\Lib\Quaternions.lib

; ------------------------------------------------------
; Constants
ifndef DM_BITSPERPEL
DM_BITSPERPEL           equ     000040000h
endif
ifndef DM_PELSWIDTH
DM_PELSWIDTH            equ     000080000h
endif
ifndef DM_PELSHEIGHT
DM_PELSHEIGHT           equ     000100000h
endif
ifndef DM_DISPLAYFREQUENCY
DM_DISPLAYFREQUENCY     equ     000400000h
endif
ifndef CDS_FULLSCREEN
CDS_FULLSCREEN          equ     000000004h
endif
ifndef ANTIALIASED_QUALITY
ANTIALIASED_QUALITY     equ     4
endif
ifndef PFD_DRAW_TO_WINDOW
PFD_DRAW_TO_WINDOW      equ     00000004h
endif
ifndef PFD_SUPPORT_OPENGL
PFD_SUPPORT_OPENGL      equ     00000020h
endif
ifndef PFD_DOUBLEBUFFER
PFD_DOUBLEBUFFER        equ     00000001h
endif
ifndef PFD_SWAP_EXCHANGE
PFD_SWAP_EXCHANGE       equ     00000200h
endif
ifndef PFD_TYPE_RGBA
PFD_TYPE_RGBA           equ     0
endif

; ------------------------------------------------------
; Structures
APPLICATION             struct
hInstance               dword   ?
APPLICATION             ends

GL_WINDOWINIT           struct
application             APPLICATION <>
winwidth                dword   ?
winheight               dword   ?
bitsPerPixel            dword   ?
GL_WINDOWINIT           ends

GL_WINDOW               struct
hWnd                    dword   ?
hDC                     dword   ?
hRC                     dword   ?
init                    GL_WINDOWINIT <>
isVisible               dword   ?
LastTickCount           LONGLONG ?
GL_WINDOW               ends

; ------------------------------------------------------
; Variables
                        .data
g_Error_Message         dd      0
g_window                GL_WINDOW <>
g_FullScreen            dd      0
g_CursorState           dd      0
g_NoSwap                dd      FALSE
g_Screen_Frequency      dd      0

_ClassName              db      "OGLW",0
_WindowName             db      "Written by Franck Charlet.",0
_PixelFormat            dd      0
_AntiAliasing           dd      0
_VSync                  dd      TRUE
_Do_AntiAliasing        dd      0
_Frames_Seconds         real4   0.0
_Frames_Counter         dd      0
_Frames_Count           dd      0
_dmScreenSettings       DEVMODE <>
wglChoosePixelFormatARB PFNWGLCHOOSEPIXELFORMATARBPROC 0
_Nbr_Sampling_Formats   dd      0
_Format_fAttributes     real4   0.0, 0.0
_Format_iAttributes     dd      WGL_DRAW_TO_WINDOW_ARB, TRUE
                        dd      WGL_SUPPORT_OPENGL_ARB, TRUE
                        dd      WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB
                        dd      WGL_COLOR_BITS_ARB
_Format_Color_Bits      dd      24
                        dd      WGL_ALPHA_BITS_ARB
_Format_Alpha_Bits      dd      8
                        dd      WGL_DEPTH_BITS_ARB
_Format_Depth_Bits      dd      16
                        dd      WGL_STENCIL_BITS_ARB
_Format_Stencil_Bits    dd      0
                        dd      WGL_DOUBLE_BUFFER_ARB, TRUE
                        dd      WGL_SAMPLE_BUFFERS_ARB, TRUE
                        dd      WGL_SAMPLES_ARB
_Format_Multi_Samples   dd      4
                        dd      0, 0

_SubEditBrush           LOGBRUSH <BS_SOLID, 0, 0>
_wtop                   dd      0
_wleft                  dd      0
pwglSwapIntervalEXT     PFNWGLSWAPINTERVALEXTPROC 0
pfd                     PIXELFORMATDESCRIPTOR < sizeof PIXELFORMATDESCRIPTOR, \
                                                1, \
                                                PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER or PFD_SWAP_EXCHANGE, \
                                                PFD_TYPE_RGBA, \
                                                0, \
                                                0, 0, 0, 0, 0, 0, \
                                                0, \
                                                0, \
                                                0, \
                                                0, 0, 0, 0, \
                                                24, \
                                                0, \
                                                0, \
                                                0, \
                                                0, \
                                                0, 0, 0 >

                        align   4               ; Required by Performance Counter
HTimerFreq              LONGLONG 0
HTimerVal               LARGE_INTEGER <>

; ------------------------------------------------------
; Public functions
Terminate_Application   proto
Initialize              proto
Deinitialize            proto
Update                  proto   :real4
Draw                    proto
Set_Frames_Counter      proto
Get_Frames_Delay        proto
Set_Error_Msg           proto   :dword
Reshape_Context         proto   :dword, :dword
Get_Pixel_Format        proto
Set_VSync               proto   :dword

                        include DInput.asm
                        include Extensions.asm
                        include Dialog.asm

; ------------------------------------------------------
; Name: Terminate_Application
; Desc: Initiate termination procedure
Terminate_Application   proc
                        invoke  PostMessage, g_window.hWnd, WM_QUIT, 0, 0
                        ret
Terminate_Application   endp

; ------------------------------------------------------
; Name: Flush_Event
; Desc: Flush the pending messages
Flush_Event             proc
                        local   msg:MSG
                        
                        invoke  PeekMessage, addr msg, NULL, 0, 0, PM_REMOVE
                        .if eax != 0
                                invoke  DispatchMessage, addr msg
                        .endif
                        ret
Flush_Event             endp

; ------------------------------------------------------
; Name: Change_Screen_Resolution
; Desc: Resize the screen with given dimensions and depth
Change_Screen_Resolution proc   w:dword, h:dword, bitsPerPixel:dword
                        invoke  RtlZeroMemory, addr _dmScreenSettings, sizeof DEVMODE
                        mov     _dmScreenSettings.dmSize, sizeof DEVMODE
                        mov     _dmScreenSettings.dmPelsWidth, CMEM(w)
                        mov     _dmScreenSettings.dmPelsHeight, CMEM(h)
                        mov     _dmScreenSettings.dmBitsPerPel, CMEM(bitsPerPixel)
                        mov     _dmScreenSettings.dmFields, DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT or DM_DISPLAYFREQUENCY
                        mov     _dmScreenSettings.dmDisplayFrequency, 60
                        invoke  ChangeDisplaySettings, addr _dmScreenSettings, CDS_FULLSCREEN
                        .if     eax != DISP_CHANGE_SUCCESSFUL
                                xor     eax, eax
                        .else
                                mov     eax, TRUE
                        .endif
                        ret
Change_Screen_Resolution endp

; -----------------------------------------------------------------------
; Name: Get_Current_Frequency
; Desc: Retrieve the monitor frequency set by the user
Get_Current_Frequency   proc
                        invoke  EnumDisplaySettings, NULL, ENUM_CURRENT_SETTINGS, addr _dmScreenSettings
                        mov     eax, _dmScreenSettings.dmDisplayFrequency
                        mov     g_Screen_Frequency, eax
                        ret
Get_Current_Frequency   endp

; -----------------------------------------------------------------------
; Name: WindowProc
; Desc: Messages handler for the main window
WindowProc              proc    hWnd:dword, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
                        local   creation:CREATESTRUCT
                        
                        .if     uMsg == WM_SYSCOMMAND
                                .if     wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER || wParam == SC_KEYMENU
                                        xor     eax, eax
                                        ret
                                .endif
                        .elseif uMsg == WM_DISPLAYCHANGE
                                invoke  Get_Current_Frequency
                        .elseif uMsg == WM_CLOSE
                                invoke  Terminate_Application
                                xor     eax, eax
                                ret
                        .elseif uMsg == WM_ACTIVATE
                                .if     g_FullScreen != FALSE
                                        mov     eax, wParam
                                        and     eax, 0ffffh
                                        mov     ecx, eax
                                        and     eax, WA_ACTIVE
                                        and     ecx, WA_CLICKACTIVE
                                        .if     eax != 0 || ecx != 0
                                                invoke  Change_Screen_Resolution, g_window.init.winwidth, g_window.init.winheight, g_window.init.bitsPerPixel
                                                invoke  GetSystemMetrics, SM_CXSCREEN
                                                push    eax
                                                invoke  GetSystemMetrics, SM_CYSCREEN
                                                mov     ecx, eax
                                                pop     eax
                                                invoke  SetWindowPos, hWnd, HWND_TOPMOST, 0, 0, eax, ecx, SWP_SHOWWINDOW
                                                invoke  Input_GotFocus
                                                mov     g_window.isVisible, TRUE
                                        .else
                                                invoke  ChangeDisplaySettings, NULL, 0
                                                invoke  SetWindowPos, hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_SHOWWINDOW
                                                invoke  ShowWindow, hWnd, SW_MINIMIZE
                                                invoke  Input_LostFocus
                                                mov     g_window.isVisible, FALSE
                                        .endif
                                .endif
                        .elseif uMsg == WM_SIZE
                                .if     wParam == SIZE_MINIMIZED
                                        invoke  Input_LostFocus
                                        mov     g_window.isVisible, FALSE
                                .elseif wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED
                                        invoke  Input_GotFocus
                                        mov     g_window.isVisible, TRUE
                                .endif
                        .elseif uMsg == WM_MOUSEMOVE
                                .if     g_CursorState == TRUE
                                        mov     g_CursorState, FALSE
                                        invoke  ShowCursor, FALSE
                                .endif
                        .elseif uMsg == WM_NCMOUSEMOVE
                                .if     g_CursorState == FALSE
                                        mov     g_CursorState, TRUE
                                        invoke  ShowCursor, TRUE
                                .endif
                        .endif
                        invoke  DefWindowProc, hWnd, uMsg, wParam, lParam
                        ret
WindowProc              endp

; -----------------------------------------------------------------------
; Name: Main
; Desc: Program entry point
Main                    proc
                        local   msg:MSG
                        local   windowClass:WNDCLASSEX
                        local   windowStyle:dword
                        local   windowExtendedStyle:dword
                        local   wwidth:dword
                        local   wheight:dword
                        local   Done_Sampling:dword
                        local   Frame_Delay:real4

                        lea     edi, g_window
                        lea     ebx, windowClass
                        invoke  RtlZeroMemory, ebx, sizeof WNDCLASSEX
                        invoke  GetModuleHandle, NULL
                        mov     [ebx + WNDCLASSEX.hInstance], eax
                        push    eax
                        pop     dword ptr [edi + GL_WINDOW.init.application.hInstance]
                        mov     dword ptr [edi + GL_WINDOW.init.winwidth], SCREEN_WIDTH
                        mov     dword ptr [edi + GL_WINDOW.init.winheight], SCREEN_HEIGHT
                        mov     dword ptr [edi + GL_WINDOW.init.bitsPerPixel], SCREEN_BPP
                        mov     dword ptr [ebx + WNDCLASSEX.cbSize], sizeof WNDCLASSEX
                        mov     dword ptr [ebx + WNDCLASSEX.style], CS_HREDRAW or CS_VREDRAW or CS_OWNDC
                        push    offset WindowProc
                        pop     dword ptr [ebx + WNDCLASSEX.lpfnWndProc]
                        invoke  GetStockObject, BLACK_BRUSH
                        mov     [ebx + WNDCLASSEX.hbrBackground], eax
                        push    offset _ClassName
                        pop     dword ptr [ebx + WNDCLASSEX.lpszClassName]
                        invoke  RegisterClassEx, addr windowClass
                        .if     eax == 0
                                invoke  Set_Error_Msg, CSTR("Can't create window class")
                                jmp     FallBack
                        .endif
                        
                        invoke  CreateFont, -8, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH or FF_SWISS, CSTR("MS Sans Serif")
                        mov     _Serif_Font, eax
                        invoke  Dialog_Create, -1, -1, 200, 103, HWND_BROADCAST, addr DialogProc, WS_BORDER or WS_CAPTION or WS_SYSMENU, TRUE
                        push    eax
                        invoke  DeleteObject, _Serif_Font
                        pop     eax
                        .if     eax == DIALOG_OK
                        .elseif eax == DIALOG_CANCEL
                                invoke  UnregisterClass, addr _ClassName, g_window.init.application.hInstance
                                ret
                        .else
                                ; Couldn't display the dialog box
                                invoke  MessageBox, 0, CSTR("Run in fullscreen ?"), addr _WindowName, MB_YESNOCANCEL or MB_ICONQUESTION
                                .if     eax == IDYES
                                        mov     g_FullScreen, TRUE
                                .elseif eax == IDNO
                                .elseif eax == IDCANCEL
                                        invoke  UnregisterClass, addr _ClassName, g_window.init.application.hInstance
                                        ret
                                .endif
                        .endif
                
; Force in window mode if constant _DEBUG is defined
ifdef _DEBUG
                        mov     g_FullScreen, FALSE
endif
                        .if     g_FullScreen == TRUE
                                mov     windowStyle, WS_POPUP
                                mov     windowExtendedStyle, WS_EX_TOPMOST
                        .else
                                mov     windowStyle, WS_BORDER or WS_CAPTION or WS_SYSMENU or WS_POPUP or WS_MINIMIZEBOX
                                mov     windowExtendedStyle, WS_EX_APPWINDOW
                        .endif

                        mov     eax, g_window.init.bitsPerPixel
                        mov     [pfd.cColorBits], al

                        mov     eax, g_window.init.winwidth
                        mov     wwidth, eax
                        mov     eax, g_window.init.winheight
                        mov     wheight, eax
                        invoke  GetSystemMetrics, SM_CXSCREEN
                        .if     wwidth > eax
                                mov     wwidth, eax
                        .endif
                        invoke  GetSystemMetrics, SM_CYSCREEN
                        .if     wheight > eax
                                mov     wheight, eax
                        .endif
                        
                        .if     g_FullScreen == FALSE
                                ; Center the window if necessary
                                invoke  GetSystemMetrics, SM_CXSCREEN
                                .if     wwidth < eax
                                        sub     eax, wwidth
                                        shr     eax, 1
                                        mov     _wleft, eax
                                .endif

                                invoke  GetSystemMetrics, SM_CYSCREEN
                                .if     wheight < eax
                                        sub     eax, wheight
                                        shr     eax, 1
                                        mov     _wtop, eax
                                .endif
                                ; Add some pixels around to make the inner part to fit the dimensions requirements
                                invoke  GetSystemMetrics, SM_CXFIXEDFRAME
                                shl     eax, 1
                                add     wwidth, eax
                                invoke  GetSystemMetrics, SM_CYFIXEDFRAME
                                shl     eax, 1
                                add     wheight, eax
                                invoke  GetSystemMetrics, SM_CYCAPTION
                                add     wheight, eax
                        .endif

                        mov     Done_Sampling, FALSE
                        mov     _AntiAliasing, FALSE
                        .if     _Do_AntiAliasing == FALSE
                                or      windowStyle, WS_VISIBLE
                        .endif
Recreate_Window:        invoke  CreateWindowEx, windowExtendedStyle, \
                                                addr _ClassName, addr _WindowName, \
                                                windowStyle, \
                                                _wleft, _wtop, wwidth, wheight, \
                                                HWND_DESKTOP, 0, \
                                                g_window.init.application.hInstance, NULL
                        mov     g_window.hWnd, eax
                        .if     eax == 0
                                invoke  Set_Error_Msg, CSTR("Can't create window")
                                jmp     FallBack
                        .endif
                        invoke  Flush_Event
                        invoke  SetForegroundWindow, g_window.hWnd
                        .if     Done_Sampling == FALSE
                                invoke  ShowCursor, FALSE
                                .if     g_FullScreen == TRUE
                                        invoke  Change_Screen_Resolution, g_window.init.winwidth, g_window.init.winheight, g_window.init.bitsPerPixel
                                        .if     eax == 0
                                                invoke  Set_Error_Msg, CSTR("Can't change screen resolution")
                                                jmp     FallBack
                                        .endif
                                        invoke  MoveWindow, g_window.hWnd, 0, 0, g_window.init.winwidth, g_window.init.winheight, 1
                                .endif
                        .endif
Use_Multi_Sampling:     .if     _Do_AntiAliasing == TRUE
                                .if     _AntiAliasing == FALSE
                                        invoke  wglGetProcAddress, CSTR("wglChoosePixelFormatARB")
                                        mov     wglChoosePixelFormatARB, eax
                                        .if     wglChoosePixelFormatARB != NULL
                                                invoke  wglMakeCurrent, g_window.hDC, 0
                                                invoke  wglDeleteContext, g_window.hRC
                                                invoke  ReleaseDC, g_window.hWnd, g_window.hDC
                                                invoke  DestroyWindow, g_window.hWnd
                                                mov     _AntiAliasing, TRUE
                                                or      windowStyle, WS_VISIBLE
                                                ; We need to recreate it entirely because SetPixelFormat can be only set 1 time for a window.
                                                jmp     Recreate_Window
                                        .endif
                                .endif
                        .endif

                        invoke  GetDC, g_window.hWnd
                        mov     g_window.hDC, eax
                        .if     eax == 0
                                jmp     Remove_Window
                        .endif

                        invoke  Get_Pixel_Format
                        mov     _PixelFormat, eax
                        .if     eax == 0
                                mov     pfd.cDepthBits, 32
                                invoke  Get_Pixel_Format
                                mov     _PixelFormat,eax
                                .if     eax == 0
                                        mov     pfd.cDepthBits, 16
                                        invoke  Get_Pixel_Format
                                        mov     _PixelFormat, eax
                                        .if     eax == 0
                                                ; Shitty Gfxcard
                                                jmp     Release_DC
                                        .endif
                                .endif
                        .endif
                        invoke  SetPixelFormat, g_window.hDC, _PixelFormat, addr pfd
                        .if     eax == FALSE
                                jmp     Release_DC
                        .endif
                        invoke  wglCreateContext, g_window.hDC
                        mov     [g_window.hRC], eax 
                        .if     eax == 0
                                jmp     Release_DC
                        .endif
                        invoke  wglMakeCurrent, g_window.hDC, g_window.hRC
                        .if     eax == FALSE
                                invoke  wglDeleteContext, g_window.hRC
Release_DC:                     invoke  ReleaseDC, g_window.hWnd, g_window.hDC
Remove_Window:                  invoke  DestroyWindow, g_window.hWnd
                                invoke  Set_Error_Msg, CSTR("Can't create opengl context")
                                jmp     FallBack
                        .endif
                        .if     _Do_AntiAliasing == TRUE
                                .if     Done_Sampling == FALSE
                                        mov     Done_Sampling, TRUE
                                        jmp     Use_Multi_Sampling
                                .endif
                        .endif
                        mov     g_window.isVisible, TRUE

                        ; Set the dimensions & projection of the window's context
                        invoke  Reshape_Context, g_window.init.winwidth, g_window.init.winheight

                        invoke  wglGetProcAddress, CSTR("wglSwapIntervalEXT")
                        mov     pwglSwapIntervalEXT, eax
                        
                        .if     _AntiAliasing == TRUE
                                invoke  glEnable, GL_MULTISAMPLE_ARB
                        .endif

                        .if     _VSync == TRUE
                                ; Turn vsync ON
                                invoke  Set_VSync, TRUE
                        .else
                                ; Turn vsync OFF
                                invoke  Set_VSync, FALSE
                        .endif

                        invoke  Get_Current_Frequency

                        invoke  Initialize
                        .if     eax == FALSE
                                invoke  Terminate_Application
                        .else
                                invoke  Get_DirectInput, g_window.hWnd
                                .if     eax == DINPUT_ERR_DINPUT
                                        invoke  Set_Error_Msg, CSTR("Can't open direct input")
                                        jmp     FallBack
                                .endif
                                
                                ; init counter
                                invoke  Set_Frames_Counter
                                mov     msg.message, 0
                                .while  msg.message != WM_QUIT
                                        invoke  PeekMessage, addr msg, NULL, 0, 0, PM_REMOVE
                                        .if     eax != 0
                                                invoke  DispatchMessage, addr msg
                                        .else
                                                .if     g_window.isVisible == FALSE
                                                        invoke  WaitMessage
                                                .else
                                                        invoke  Mouse_Read
                                                        invoke  Keyboard_Read
                                                        invoke  Get_Frames_Delay
                                                        fstp    Frame_Delay
                                                        invoke  Update, Frame_Delay
                                                        invoke  Draw
                                                        .if     g_NoSwap == FALSE
                                                                invoke  SwapBuffers, g_window.hDC
                                                        .endif
                                                .endif
                                        .endif
                                .endw
                                invoke  Release_DirectInput
                        .endif
                        
                        invoke  Deinitialize
                        invoke  ChangeDisplaySettings, NULL, 0
                        .if     g_window.hWnd != 0
                                .if     g_window.hDC != 0
                                        invoke  wglMakeCurrent, g_window.hDC, 0
                                        .if     g_window.hRC != 0
                                                invoke  wglDeleteContext, g_window.hRC
                                        .endif
                                        invoke  ReleaseDC, g_window.hWnd, g_window.hDC
                                .endif
                                invoke  DestroyWindow, g_window.hWnd
                        .endif
                        invoke  ShowCursor, TRUE
                        invoke  UnregisterClass, addr _ClassName, g_window.init.application.hInstance
FallBack:               invoke  Flush_Event
                        .if g_Error_Message != NULL
                                invoke  MessageBox, HWND_DESKTOP, g_Error_Message, addr _WindowName, MB_ICONERROR or MB_OK
                        .endif
                        ret
Main                    endp

; ------------------------------------------------------
; Name: Set_Frames_Counter
; Desc: Init the frames counter
Set_Frames_Counter      proc
                        invoke  QueryPerformanceFrequency, addr HTimerVal
                        fild    HTimerVal.QuadPart
                        fistp   HTimerFreq
                        invoke  QueryPerformanceCounter, addr HTimerVal
                        fild    HTimerVal.QuadPart
                        fistp   g_window.LastTickCount
                        ret
Set_Frames_Counter      endp

; ------------------------------------------------------
; Name: Get_Frames_Delay
; Desc: Amount of milliseconds between 2 frames
Get_Frames_Delay        proc
                        local   Delay:real4

                        invoke  QueryPerformanceCounter, addr HTimerVal
                        fild    HTimerVal.QuadPart
                        fild    g_window.LastTickCount
                        fsubp   st(1), st(0)
                        fild    HTimerFreq
                        fdivp   st(1), st(0)
                        fstp    Delay
                        fild    HTimerVal.QuadPart
                        fistp   g_window.LastTickCount
                        fld     Delay
                        ret
Get_Frames_Delay        endp

; ------------------------------------------------------
; Name: Set_Error_Msg
; Desc: Load the g_Error_Message variable
Set_Error_Msg           proc    Msg:dword
                        mov     eax, Msg
                        mov     g_Error_Message, eax
                        ret
Set_Error_Msg           endp

; ------------------------------------------------------
; Name: Set_VSync
; Desc: Turn vertical synchro on/off
Set_VSync               proc    Status:dword
                        .if     pwglSwapIntervalEXT != NULL
                                invoke  pwglSwapIntervalEXT, Status
                        .endif
                        ret
Set_VSync               endp

; ------------------------------------------------------
; Name: Reshape_GL
; Desc: Resize the opengl frame according to the screen/window's one
Reshape_Context         proc    _Width:dword, Height:dword
                        local   _fW:real8
                        local   _mfW:real8
                        local   _mfH:real8

                        ; Set the projection matrix
                        invoke  glViewport, 0, 0, _Width, Height
                        invoke  glMatrixMode, GL_PROJECTION
                        invoke  glLoadIdentity
                        fld     CDBL(0.0049999998882413)
                        fld     st(0)
                        fchs
                        fstp    qword ptr [_mfH]
                        fild    dword ptr [_Width]
                        fidiv   dword ptr [Height]
                        fmulp   st(1),st(0)
                        fst     qword ptr [_fW]
                        fchs
                        fstp    qword ptr [_mfW]
                        invoke  glFrustum, _mfW, _fW, _mfH, CDBL(0.0049999998882413), CDBL(0.01), CDBL(500.0)
                        invoke  glMatrixMode, GL_MODELVIEW
                        invoke  glLoadIdentity
                        ret
Reshape_Context         endp

; ------------------------------------------------------
; Name: Get_Pixel_Format
; Desc: Obtain a suitable pixel format
Get_Pixel_Format        proc
                        local   PixelFormat:dword

                        .if     _AntiAliasing == TRUE
                                movzx   eax, pfd.cColorBits
                                mov     _Format_Color_Bits, eax
                                movzx   eax, pfd.cAlphaBits
                                mov     _Format_Alpha_Bits, eax
                                movzx   eax, pfd.cDepthBits
                                mov     _Format_Depth_Bits, eax
                                movzx   eax, pfd.cStencilBits
                                mov     _Format_Stencil_Bits, eax
                                invoke  wglChoosePixelFormatARB, g_window.hDC, addr _Format_iAttributes, addr _Format_fAttributes, 1, addr PixelFormat, addr _Nbr_Sampling_Formats
                                .if     eax == TRUE && _Nbr_Sampling_Formats >= 1
                                        mov     eax, PixelFormat
                                .else
Try_Sampling:                           ; Try lower sampling until we reach a suitable level
                                        sub     _Format_Multi_Samples, 2
                                        invoke  wglChoosePixelFormatARB, g_window.hDC, addr _Format_iAttributes, addr _Format_fAttributes, 1, addr PixelFormat, addr _Nbr_Sampling_Formats
                                        .if     eax == TRUE && _Nbr_Sampling_Formats >= 1
                                                mov     eax, PixelFormat
                                        .else
                                                .if     _Format_Multi_Samples <= 2
                                                        ; No anti-aliasing
                                                        invoke  ChoosePixelFormat, g_window.hDC, addr pfd
                                                        mov     _AntiAliasing, FALSE
                                                .else
                                                        jmp     Try_Sampling
                                                .endif
                                        .endif
                                .endif
                        .else 
                                ; (ChoosePixelFormat returns the pixel format in eax)
                                invoke  ChoosePixelFormat, g_window.hDC, addr pfd
                                mov     _AntiAliasing, FALSE
                        .endif
                        ret
Get_Pixel_Format        endp

; ------------------------------------------------------
; Name: Calc_FPS
; Desc: Calculate the number of frames per second
Calc_FPS                proc    FrameRate:real4
                        .if     g_FullScreen == 0
                                fld     FrameRate
                                fadd    _Frames_Seconds
                                fstp    _Frames_Seconds
                                inc     _Frames_Counter
                                FCMP    _Frames_Seconds, CFLT(1.0)              ; Refresh it every second
                                jb      Wait_Fps
                                ; Save the number of frames
                                push    _Frames_Counter
                                pop     _Frames_Count
                                mov     _Frames_Seconds, 0
                                mov     _Frames_Counter, 0
                        .endif
Wait_Fps:               mov     eax, _Frames_Count
                        ret
Calc_FPS                endp

; ------------------------------------------------------
; Name: start
; Desc: Start of the program
start:                  invoke  Main
                        invoke  ExitProcess, 0
