program field;

uses
  Windows,
  Messages,
  dglOpenGL;

const
  WND_TITLE = 'OpenGL Template using OpenGL 1.5 by McCLaw';
  FPS_TIMER = 1;                     // Timer to calculate FPS
  FPS_INTERVAL = 1000;               // Calculate FPS every 1000 ms

  // User Constants
  FRUSTDIM: GLdouble = 100.0;
  FRUSTNEAR: GLdouble = 320.0;
  FRUSTFAR: GLdouble = 660.0;
  wall_mat: array [0..3] of GLfloat = (1.0, 1.0, 1.0, 1.0);
  lightpos: array [0..3] of GLfloat = (50.0, 50.0, -320.0, 1.0);
  sphere_mat: array [0..3] of GLfloat = (1.0, 0.5, 0.0, 1.0);
  cone_mat: array [0..3] of GLfloat = (0.0, 0.5, 1.0, 1.0);


var
  h_Wnd  : HWND;                     // Global window handle
  h_DC   : HDC;                      // Global device context
  h_RC   : HGLRC;                    // OpenGL rendering context
  keys : Array[0..255] of Boolean;   // Holds keystrokes
  FPSCount : Integer = 0;            // Counter for FPS
  ElapsedTime : Integer;             // Elapsed time between frames

  // Textures
  Texture : GLuint;                  // Variable to hold the texture pointer

  // User vaiables
  xSpeed, ySpeed : glFloat;
  xAngle, yAngle : glFloat;

  // Mouse Variables
  MouseMove : boolean = false;        // Is the mouse moving?
  MoveXcoord, MoveYcoord : GLfloat;   // Current X and Y position of the cursor

  MouseButton : Integer = -1;         // mouse button down
  Xcoord, Ycoord : Integer;           // Current X and Y position where the mouse was clicked

  OpenGLInitialized : Boolean;

  LSphere: GLint = 1;
  LCone: GLint = 2;

  focus: GLFloat = 420.0;

{$R *.RES}

{------------------------------------------------------------------}
{  Function to convert int to string. (No sysutils = smaller EXE)  }
{------------------------------------------------------------------}
function IntToStr(Num : Integer) : String;  // using SysUtils increase file size by 100K
begin
  Str(Num, result);
end;

procedure glDrawScene();
begin


  //*
  //** Note: wall verticies are ordered so they are all front facing
  //** this lets me do back face culling to speed things up.
  //*/

  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @wall_mat);

  //* floor */
  //* make the floor textured */
  glEnable(GL_TEXTURE_2D);

  //*
  //** Since we want to turn texturing on for floor only, we have to
  //** make floor a separate glBegin()/glEnd() sequence. You can't
  //** turn texturing on and off between begin and end calls
  //*/
  glBegin(GL_QUADS);
  glNormal3f(0.0, 1.0, 0.0);
  glTexCoord2i(0, 0);
  glVertex3f(-100.0, -100.0, -320.0);
  glTexCoord2i(1, 0);
  glVertex3f( 100.0, -100.0, -320.0);
  glTexCoord2i(1, 1);
  glVertex3f( 100.0, -100.0, -640.0);
  glTexCoord2i(0, 1);
  glVertex3f(-100.0, -100.0, -640.0);
  glEnd();

  glDisable(GL_TEXTURE_2D);

  //* walls */


  glBegin(GL_QUADS);

  //* left wall */
  glNormal3f(1.0, 0.0, 0.0);
  glVertex3f(-100.0, -100.0, -320.0);
  glVertex3f(-100.0, -100.0, -640.0);
  glVertex3f(-100.0,  100.0, -640.0);
  glVertex3f(-100.0,  100.0, -320.0);

  //* right wall */
  glNormal3f(-1.0, 0.0, 0.0);
  glVertex3f( 100.0, -100.0, -320.0);
  glVertex3f( 100.0,  100.0, -320.0);
  glVertex3f( 100.0,  100.0, -640.0);
  glVertex3f( 100.0, -100.0, -640.0);

  //* ceiling */
  glNormal3f(0.0, -1.0, 0.0);
  glVertex3f(-100.0,  100.0, -320.0);
  glVertex3f(-100.0,  100.0, -640.0);
  glVertex3f( 100.0,  100.0, -640.0);
  glVertex3f( 100.0,  100.0, -320.0);

  //* back wall */
  glNormal3f(0.0, 0.0, 1.0);
  glVertex3f(-100.0, -100.0, -640.0);
  glVertex3f( 100.0, -100.0, -640.0);
  glVertex3f( 100.0,  100.0, -640.0);
  glVertex3f(-100.0,  100.0, -640.0);
  glEnd();


  glPushMatrix();
  glTranslatef(-80.0, -60.0, -420.0);
  glCallList(LSPHERE);
  glPopMatrix();


  glPushMatrix();
  glTranslatef(-20.0, -80.0, -600.0);
  glCallList(LCONE);
  glPopMatrix();

  glFlush(); //* high end machines may need this */
end;

{------------------------------------------------------------------}
{  Function to draw the actual scene                               }
{------------------------------------------------------------------}
procedure glDraw();
var
  min, max, count,i , j  : integer;
  scale, dx, dy: GLfloat;
begin
(*
  //Standard Render Mode
  glLoadIdentity();
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-FRUSTDIM, FRUSTDIM, -FRUSTDIM, FRUSTDIM, FRUSTNEAR, FRUSTFAR);
  glMatrixMode(GL_MODELVIEW);
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
  glDrawScene;
*)


  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  //Field Render Mode
  min := -2;
  max := -min + 1;
  count := -2 * min + 1;
  count := count*count;

  scale := 2.0;

  glClear(GL_ACCUM_BUFFER_BIT);

  for j := min to max-1 do
  begin
       for i := min to max-1 do
       begin
          dx := scale * i * FRUSTNEAR/focus;
          dy := scale * j * FRUSTNEAR/focus;
          glMatrixMode(GL_PROJECTION);
          glLoadIdentity();
          glFrustum(-FRUSTDIM + dx,
                    FRUSTDIM + dx,
                    -FRUSTDIM + dy,
                    FRUSTDIM + dy,
                    FRUSTNEAR,
                    FRUSTFAR);
          glMatrixMode(GL_MODELVIEW);
          glLoadIdentity();
          glTranslatef(scale * i, scale * j, 0.0);
          glDrawScene();
          glAccum(GL_ACCUM, 1.0/count);
        end;
  end;
      glAccum(GL_RETURN, 1.0);



  //Swap Buffers
  SwapBuffers(h_DC); // Display the scene


end;


{------------------------------------------------------------------}
{  Initialise OpenGL                                               }
{------------------------------------------------------------------}
procedure glInit();
var
  sphere, cone, base : PGLUquadricObj;
begin

  xSpeed :=0.1;   // start with some movement
  ySpeed :=0.1;

  //* turn on features */
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  //* place light 0 in the right place */
  glLightfv(GL_LIGHT0, GL_POSITION, @lightpos);


  //* remove back faces to speed things up */
  glCullFace(GL_BACK);

//  glShadeModel(GL_SMOOTH);			                    // Povolí jemné stínování
  glClearColor(0.0, 0.0, 0.0, 0.5);	  	            // Černé pozadí
//  glClearDepth(1.0);				                        // Nastavení hloubkového bufferu
//  glEnable(GL_DEPTH_TEST);			                    // Povolí hloubkové testování
//  glDepthFunc(GL_LEQUAL);				                    // Typ hloubkového testování
  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // Nejlepší perspektivní korekce


  //make display lists
  glNewList(LSPHERE, GL_COMPILE);
  //* make display lists for sphere and cone; for efficiency */
  sphere := gluNewQuadric();
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @sphere_mat);
  gluSphere(sphere, 20.0, 20, 20);
  gluDeleteQuadric(sphere);
  glEndList();

  glNewList(LCONE, GL_COMPILE);
  cone := gluNewQuadric();
  base := gluNewQuadric();
  glRotatef(-90.0, 1.0, 0.0, 0.0);
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @cone_mat);
  gluDisk(base, 0., 20., 20, 1);
  gluCylinder(cone, 20., 0., 60., 20, 20);
  gluDeleteQuadric(cone);
  gluDeleteQuadric(base);
  glEndList();



end;


{------------------------------------------------------------------}
{  Handle window resize                                            }
{------------------------------------------------------------------}
procedure glResizeWnd(Width, Height : Integer);
begin
//  if (Height = 0) then                // prevent divide by zero exception
//    Height := 1;
//  glViewport(0, 0, Width, Height);    // Set the viewport for the OpenGL window


  if (Height=0) then		                                  // Zabezpečení proti dělení nulou
     Height:=1;                                           // Nastaví výšku na jedna
  glViewport(0, 0, Width, Height);                        // Resetuje aktuální nastavení
  glMatrixMode(GL_PROJECTION);                            // Zvolí projekční matici
  glLoadIdentity();                                       // Reset matice
  gluPerspective(45.0,Width/Height,0.1,1000.0);            // Výpočet perspektivy
  glMatrixMode(GL_MODELVIEW);                             // Zvolí matici Modelview
  glLoadIdentity;                                         // Reset matice


end;

{------------------------------------------------------------------}
{  Processes all the mouse move                                  }
{------------------------------------------------------------------}
procedure ProcessMouseMove();
begin
  if MouseMove then
  begin
    // Add Code here to execute on mouse move
    MouseMove := False;
  end;
end;

{------------------------------------------------------------------}
{  Processes all the mouse clicks                                  }
{------------------------------------------------------------------}
procedure ProcessMouseClick;
begin
  case MouseButton of
  1: // Left Mouse Button
    begin
      // Add code to execute on mouse click
      MouseButton := 0; // Cancel our mouse click (To use this procedure as a mouse down event remove this line)
    end;
  2: // Right Mouse Button
    begin
      // Add code to execute on mouse click
      MouseButton := 0; // Cancel our mouse click (To use this procedure as a mouse down event remove this line)
    end;
  3: // Middle Mouse Button
    begin
      // Add code to execute on mouse click
      MouseButton := 0;  // Cancel our mouse click (To use this procedure as a mouse down event remove this line)
    end;
  end;
end;

{------------------------------------------------------------------}
{  Processes all the keystrokes                                    }
{------------------------------------------------------------------}
procedure ProcessKeys;
begin
  if (keys[VK_UP])    then xspeed := xspeed - 0.002;
  if (keys[VK_DOWN])  then xspeed := xspeed + 0.002;
  if (keys[VK_RIGHT]) then yspeed := yspeed + 0.002;
  if (keys[VK_LEFT])  then yspeed := yspeed - 0.002;
end;


{------------------------------------------------------------------}
{  Determines the application’s response to the messages received  }
{------------------------------------------------------------------}
function WndProc(hWnd: HWND; Msg: UINT;  wParam: WPARAM;  lParam: LPARAM): LRESULT; stdcall;
begin
  case (Msg) of
    WM_CREATE:
      begin
        // Insert stuff you want executed when the program starts
      end;
    WM_CLOSE:
      begin
        PostQuitMessage(0);
        Result := 0
      end;
    WM_KEYDOWN:       // Set the pressed key (wparam) to equal true so we can check if its pressed
      begin
        keys[wParam] := True;
        Result := 0;
      end;
    WM_KEYUP:         // Set the released key (wparam) to equal false so we can check if its pressed
      begin
        keys[wParam] := False;
        Result := 0;
      end;
    WM_MOUSEMOVE:
      begin
        MouseMove := True;
        MoveXcoord := LOWORD(lParam);
        MoveYcoord := HIWORD(lParam);
        Result := 0;
      end;
    WM_LBUTTONDOWN:
      begin
        ReleaseCapture();   // need them here, because if mouse moves off
        SetCapture(h_Wnd);  // window and returns, it needs to reset status
        MouseButton := 1;
        Xcoord := LOWORD(lParam);
        Ycoord := HIWORD(lParam);
        Result := 0;
      end;
    WM_RBUTTONDOWN:
      begin
        ReleaseCapture();   // need them here, because if mouse moves off
        SetCapture(h_Wnd);  // window and returns, it needs to reset status
        MouseButton := 2;
        Xcoord := LOWORD(lParam);
        Ycoord := HIWORD(lParam);
        Result := 0;
      end;
    WM_MBUTTONDOWN:
      begin
        ReleaseCapture();   // need them here, because if mouse moves off
        SetCapture(h_Wnd);  // window and returns, it needs to reset status
        MouseButton := 3;
        Xcoord := LOWORD(lParam);
        Ycoord := HIWORD(lParam);
        Result := 0;
      end;
    WM_LBUTTONUP,WM_RBUTTONUP,WM_MBUTTONUP:
      begin
        ReleaseCapture();   // above
        MouseButton := 0;
        XCoord := 0;
        YCoord := 0;
        Result := 0;
      end;
    WM_SIZE:          // Resize the window with the new width and height
      begin
        if OpenGLInitialized then
         glResizeWnd(LOWORD(lParam),HIWORD(lParam));
        Result := 0;
      end;
    WM_TIMER :                     // Add code here for all timers to be used.
      begin
        if wParam = FPS_TIMER then
        begin
          FPSCount :=Round(FPSCount * 1000/FPS_INTERVAL);   // calculate to get per Second incase intercal is less or greater than 1 second
          SetWindowText(h_Wnd, PChar(WND_TITLE + '   [' + intToStr(FPSCount) + ' FPS]'));
          FPSCount := 0;
          Result := 0;
        end;
      end;
    else
      begin
      
      Result := DefWindowProc(hWnd, Msg, wParam, lParam);    // Default result if nothing happens
      end;
  end;
end;


{---------------------------------------------------------------------}
{  Properly destroys the window created at startup (no memory leaks)  }
{---------------------------------------------------------------------}
procedure glKillWnd(Fullscreen : Boolean);
begin
  if Fullscreen then             // Change back to non fullscreen
  begin
    ChangeDisplaySettings(devmode(nil^), 0);
    ShowCursor(True);
  end;

  // Makes current rendering context not current, and releases the device
  // context that is used by the rendering context.
  if (not wglMakeCurrent(h_DC, 0)) then
    MessageBox(0, 'Release of DC and RC failed!', 'Error', MB_OK or MB_ICONERROR);

  // Attempts to delete the rendering context
  if (not wglDeleteContext(h_RC)) then
  begin
    MessageBox(0, 'Release of rendering context failed!', 'Error', MB_OK or MB_ICONERROR);
    h_RC := 0;
  end;

  // Attemps to release the device context
  if ((h_DC > 0) and (ReleaseDC(h_Wnd, h_DC) = 0)) then
  begin
    MessageBox(0, 'Release of device context failed!', 'Error', MB_OK or MB_ICONERROR);
    h_DC := 0;
  end;

  // Attempts to destroy the window
  if ((h_Wnd <> 0) and (not DestroyWindow(h_Wnd))) then
  begin
    MessageBox(0, 'Unable to destroy window!', 'Error', MB_OK or MB_ICONERROR);
    h_Wnd := 0;
  end;

  // Attempts to unregister the window class
  if (not UnRegisterClass('OpenGL', hInstance)) then
  begin
    MessageBox(0, 'Unable to unregister window class!', 'Error', MB_OK or MB_ICONERROR);
    hInstance := 0;
  end;
end;


{--------------------------------------------------------------------}
{  Creates the window and attaches a OpenGL rendering context to it  }
{--------------------------------------------------------------------}
function glCreateWnd(Width, Height : Integer; Fullscreen : Boolean; PixelDepth : Integer) : Boolean;
var
  wndClass : TWndClass;         // Window class
  dwStyle : DWORD;              // Window styles
  dwExStyle : DWORD;            // Extended window styles
  dmScreenSettings : DEVMODE;   // Screen settings (fullscreen, etc...)
  PixelFormat : GLuint;         // Settings for the OpenGL rendering
  h_Instance : HINST;           // Current instance
  pfd : TPIXELFORMATDESCRIPTOR;  // Settings for the OpenGL window
begin
  InitOpenGL;                               // New call to initialize and bind the OpenGL dll

  h_Instance := GetModuleHandle(nil);       //Grab An Instance For Our Window
  ZeroMemory(@wndClass, SizeOf(wndClass));  // Clear the window class structure

  with wndClass do                    // Set up the window class
  begin
    style         := CS_HREDRAW or    // Redraws entire window if length changes
                     CS_VREDRAW or    // Redraws entire window if height changes
                     CS_OWNDC;        // Unique device context for the window
    lpfnWndProc   := @WndProc;        // Set the window procedure to our func WndProc
    hInstance     := h_Instance;
    hCursor       := LoadCursor(0, IDC_ARROW);
    lpszClassName := 'OpenGL';
  end;

  if (RegisterClass(wndClass) = 0) then  // Attemp to register the window class
  begin
    MessageBox(0, 'Failed to register the window class!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit
  end;

  // Change to fullscreen if so desired
  if Fullscreen then
  begin
    ZeroMemory(@dmScreenSettings, SizeOf(dmScreenSettings));
    with dmScreenSettings do begin              // Set parameters for the screen setting
      dmSize       := SizeOf(dmScreenSettings);
      dmPelsWidth  := Width;                    // Window width
      dmPelsHeight := Height;                   // Window height
      dmBitsPerPel := PixelDepth;               // Window color depth
      dmFields     := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL;
    end;

    // Try to change screen mode to fullscreen
    if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) = DISP_CHANGE_FAILED) then
    begin
      MessageBox(0, 'Unable to switch to fullscreen!', 'Error', MB_OK or MB_ICONERROR);
      Fullscreen := False;
    end;
  end;

  // If we are still in fullscreen then
  if (Fullscreen) then
  begin
    dwStyle := WS_POPUP or                // Creates a popup window
               WS_CLIPCHILDREN            // Doesn't draw within child windows
               or WS_CLIPSIBLINGS;        // Doesn't draw within sibling windows
    dwExStyle := WS_EX_APPWINDOW;         // Top level window
    ShowCursor(False);                    // Turn of the cursor (gets in the way)
  end
  else
  begin
    dwStyle := WS_OVERLAPPEDWINDOW or     // Creates an overlapping window
               WS_CLIPCHILDREN or         // Doesn't draw within child windows
               WS_CLIPSIBLINGS;           // Doesn't draw within sibling windows
    dwExStyle := WS_EX_APPWINDOW or       // Top level window
                 WS_EX_WINDOWEDGE;        // Border with a raised edge
  end;

  // Attempt to create the actual window
  h_Wnd := CreateWindowEx(dwExStyle,      // Extended window styles
                          'OpenGL',       // Class name
                          WND_TITLE,      // Window title (caption)
                          dwStyle,        // Window styles
                          0, 0,           // Window position
                          Width, Height,  // Size of window
                          0,              // No parent window
                          0,              // No menu
                          h_Instance,     // Instance
                          nil);           // Pass nothing to WM_CREATE

  if h_Wnd = 0 then
  begin
    glKillWnd(Fullscreen);                // Undo all the settings we've changed
    MessageBox(0, 'Unable to create window!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Try to get a device context
  h_DC := GetDC(h_Wnd);
  if (h_DC = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to get a device context!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Settings for the OpenGL window
  with pfd do
  begin
    nSize           := SizeOf(TPIXELFORMATDESCRIPTOR); // Size Of This Pixel Format Descriptor
    nVersion        := 1;                    // The version of this data structure
    dwFlags         := PFD_DRAW_TO_WINDOW    // Buffer supports drawing to window
                       or PFD_SUPPORT_OPENGL // Buffer supports OpenGL drawing
                       or PFD_DOUBLEBUFFER;  // Supports double buffering
    iPixelType      := PFD_TYPE_RGBA;        // RGBA color format
    cColorBits      := PixelDepth;           // OpenGL color depth
    cRedBits        := 0;                    // Number of red bitplanes
    cRedShift       := 0;                    // Shift count for red bitplanes
    cGreenBits      := 0;                    // Number of green bitplanes
    cGreenShift     := 0;                    // Shift count for green bitplanes
    cBlueBits       := 0;                    // Number of blue bitplanes
    cBlueShift      := 0;                    // Shift count for blue bitplanes
    cAlphaBits      := 0;                    // Not supported
    cAlphaShift     := 0;                    // Not supported
    cAccumBits      := PixelDepth;           // No accumulation buffer
    cAccumRedBits   := 0;                    // Number of red bits in a-buffer
    cAccumGreenBits := 0;                    // Number of green bits in a-buffer
    cAccumBlueBits  := 0;                    // Number of blue bits in a-buffer
    cAccumAlphaBits := 0;                    // Number of alpha bits in a-buffer
    cDepthBits      := 16;                   // Specifies the depth of the depth buffer
    cStencilBits    := 0;                    // Turn off stencil buffer
    cAuxBuffers     := 0;                    // Not supported
    iLayerType      := PFD_MAIN_PLANE;       // Ignored
    bReserved       := 0;                    // Number of overlay and underlay planes
    dwLayerMask     := 0;                    // Ignored
    dwVisibleMask   := 0;                    // Transparent color of underlay plane
    dwDamageMask    := 0;                     // Ignored
  end;

  // Attempts to find the pixel format supported by a device context that is the best match to a given pixel format specification.
  PixelFormat := ChoosePixelFormat(h_DC, @pfd);
  if (PixelFormat = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to find a suitable pixel format', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Sets the specified device context's pixel format to the format specified by the PixelFormat.
  if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to set the pixel format', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Create a OpenGL rendering context
  h_RC := wglCreateContext(h_DC);
  if (h_RC = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to create an OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Makes the specified OpenGL rendering context the calling thread's current rendering context
  if (not wglMakeCurrent(h_DC, h_RC)) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;
  // Read And Assign Extentions
  ReadExtensions;
  ReadImplementationProperties;
  OpenGLInitialized := True;
  // Initializes the timer used to calculate the FPS
  SetTimer(h_Wnd, FPS_TIMER, FPS_INTERVAL, nil);

  // Settings to ensure that the window is the topmost window
  ShowWindow(h_Wnd, SW_SHOW);
  SetForegroundWindow(h_Wnd);
  SetFocus(h_Wnd);

  // Ensure the OpenGL window is resized properly
  glResizeWnd(Width, Height);
  glInit();

  Result := True;
end;


{--------------------------------------------------------------------}
{  Main message loop for the application                             }
{--------------------------------------------------------------------}
function WinMain(hInstance : HINST; hPrevInstance : HINST;
                 lpCmdLine : PChar; nCmdShow : Integer) : Integer; stdcall;
var
  msg : TMsg;
  finished : Boolean;
  DemoStart, LastTime : DWord;
begin
  finished := False;

  // Perform application initialization:
  if not glCreateWnd(512, 512, FALSE, 32) then
  begin
    Result := 0;
    Exit;
  end;

  DemoStart := GetTickCount();            // Get Time when demo started

  // Main message loop:
  while not finished do
  begin
    if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // Check if there is a message for this window
    begin
      if (msg.message = WM_QUIT) then     // If WM_QUIT message received then we are done
        finished := True
      else
      begin                               // Else translate and dispatch the message to this window
  	TranslateMessage(msg);
        DispatchMessage(msg);
      end;
    end
    else
    begin
      Inc(FPSCount);                      // Increment FPS Counter

      LastTime :=ElapsedTime;
      ElapsedTime :=GetTickCount() - DemoStart;     // Calculate Elapsed Time
      ElapsedTime :=(LastTime + ElapsedTime) DIV 2; // Average it out for smoother movement

      glDraw();                           // Draw the scene
      SwapBuffers(h_DC);                  // Display the scene

      if (keys[VK_ESCAPE]) then           // If user pressed ESC then set finised TRUE
        finished := True
      else
      begin
        ProcessKeys;                      // Check for any other key Pressed
        ProcessMouseMove;                 // Check for mouse move
        ProcessMouseClick;                // Check for Mouse Click
      end;
    end;
  end;
  glKillWnd(FALSE);
  Result := msg.wParam;
end;


begin
  WinMain( hInstance, hPrevInst, CmdLine, CmdShow );
end.

