/*

  glDemo.c - An OpenGL demo project

  This program was written as an example of how you can write an OpenGL based program
  and have the main display either in a window or full-screen with various resolutions
  and color depths.

  There are several options allowed on the command line.  They are:
  -height : what window/screen height do you want to use?
  -width  : what window/screen width do you want to use?
  -bpp    : what color depth do you want to use?
  -window : create a rendering window rather than full-screen
  -fov    : use a field of view other than 65 degrees

  The program uses a texture that is 64x64 in dimension and is a raw RGB dump.  It displays
  a texture mapped triangle that rotates in the middle of the screen. The triangle appears
  to rest on a medium gray plane which is not textured.

  There is no camera movement possible and only a single keystroke is used.  Escape exits
  the program.

  This program has been tested on every OpenGL driver I have and it works on all of them.
  Some only work in full screen mode because either the hardware doesn't support windowed
  rendering or the driver doesn't work properly for windowed rendering.

  It has been tested with the following video cards and their OpenGL drivers:
  (these are in alphabet order)

  3Dfx Voodoo/Voodoo Rush/Voodoo II (Mesa only so far)
  AccelGraphics Eclipse II (Evans & Sutherland)
  ATI Rage Pro
  Glint 500 (3Dlabs)
  InterGraph Realizm Z13
  nVidia Riva 128
  Oxygen (Dynamic Pictures)
  Permedia 2 (3Dlabs)
  PowerVR PCX2 (NEC / VideoLogic)
  Rendition V2X00

  The program has been tested under Windows 95, Windows 95 OEMR2 and Windows NT V4.0. It
  has NOT been tested under Windows 98 nor has it been tested under NT 5.0.

  It will use the first OPENGL32.DLL it finds so if you have a 3D only card, you need to
  put the drivers for it in the same directory as the program.  It also uses GLU32.DLL
  but the ones from Microsoft's software drivers will work.

  Special thanks goes to John Carmack letting me peek over his shoulder, so to speak, for
  some sample code.

  Bruce Lewis

*/

#include <windows.h>
#include <stdio.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <fcntl.h>
#include <io.h>
#include "gldemo.h"

windata_t   WinData;
devinfo_t   DevInfo;

int         Texture;
float       fAngle = 0.0f;

char       *szFSDesc[] = { "Windowed", "Full Screen" };
char        szAppName[] = "glDemo";

BOOL             CreateMainWindow( int width, int height, int bpp, BOOL fullscreen);
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
   {
    MSG         msg;
    int         i;
    HDC         hdc;

    // Not changable by user
    WinData.hInstance    = hInstance;
    WinData.iCmdShow     = iCmdShow;
    WinData.wndproc      = (WNDPROC)WndProc;
    WinData.pResolutions = 0;
    WinData.NearClip     = 2.0f;
    WinData.FarClip      = 512.0f;

    // User definable
    WinData.fov          = 65.0f;
    WinData.bAllowSoft   = TRUE;
    WinData.bFullScreen  = TRUE;

    // Get the current display device info
    hdc = GetDC( NULL );
    DevInfo.bpp    = GetDeviceCaps(hdc, BITSPIXEL);
    DevInfo.width  = GetSystemMetrics(SM_CXSCREEN);
    DevInfo.height = GetSystemMetrics(SM_CYSCREEN);
    ReleaseDC(NULL, hdc);

    // Parse the command line if there is one
    WinData.argc = 0;
    if (strlen(szCmdLine) > 0)
       {
        WinData.szCmdLine = szCmdLine;
        GetParameters();
       }

    // Default to 640 pixels wide
    if ((i = FindNumParameter("-width")) != -1)
       {
        WinData.width = i;
       }
    else
       {
        WinData.width = 640;
       }

    // Default to 480 pixels high
    if ((i = FindNumParameter("-height")) != -1)
       {
        WinData.height = i;
       }
    else
       {
        WinData.height = 480;
       }

    // Default to 16 bits of color per pixel
    if ((i = FindNumParameter("-bpp")) != -1)
       {
        WinData.bpp = i;
       }
    else
       {
        WinData.bpp = 16;
       }

    // Default to a 65 degree field of view
    if ((i = FindNumParameter("-fov")) != -1)
       {
        WinData.fov = (float)i;
       }
    else
       {
        WinData.fov = 65.0f;
       }

    // Check for windowed rendering
    if (FindParameter("-window"))
       {
        WinData.bFullScreen = FALSE;
       }

    // Build up the video mode list
    BuildModeList();

    // Set the desired video mode and/or color depth
    if (!SetVideoMode())
       {
        Cleanup();
        return 0;
       }

    // Create the main program window, start up OpenGL and create our viewport
    if (CreateMainWindow( WinData.width, WinData.height, WinData.bpp, WinData.bFullScreen) != TRUE)
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "Unable to create main window.\nProgram will now end.", "FATAL ERROR", MB_OK);
        Cleanup();
        return 0;
       }

    // Turn the cursor off for full-screen mode
    if (WinData.bFullScreen == TRUE)
       { // Probably want to do this all the time anyway
        ShowCursor(FALSE);
       }

    // Load the demonstration texture
    LoadTexture();

    // We're live now
    WinData.bActive = TRUE;

    // Begin the main program loop
    while (WinData.bActive == TRUE)
       {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
           {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
           }
        if (WinData.hGLRC)
           {
            RenderScene();
           }
       }
    if (WinData.bFullScreen == TRUE)
       {
        ShowCursor(TRUE);
       }
    // Release the parameter and video resolution lists
    Cleanup();
    return msg.wParam;
   }

void GetParameters()
   {
    int   count;
    char *s, *tstring;

    // Make a copy of the command line to count the parameters - strtok is destructive
    tstring = (char *)malloc(sizeof(char)*(strlen(WinData.szCmdLine)+1));
    strcpy(tstring, WinData.szCmdLine);

    // Count the parameters
    s = strtok(tstring, " ");
    count = 1;
    while (strtok(NULL, " ") != NULL)
       {
        count++;
       }
    free(tstring);

    // Allocate "pockets" for the parameters
    WinData.argv = (char **)malloc(sizeof(char*)*(count+1));

    // Copy first parameter into the "pockets"
    WinData.argc = 0;
    s = strtok(WinData.szCmdLine, " ");
    WinData.argv[WinData.argc] = (char *)malloc(sizeof(char)*(strlen(s)+1));
    strcpy(WinData.argv[WinData.argc], s);
    WinData.argc++;

    // Copy the rest of the parameters
    do
       {
        // get the next token
        s = strtok(NULL, " ");
        if (s != NULL)
           { 
            // add it to the list
            WinData.argv[WinData.argc] = (char *)malloc(sizeof(char)*(strlen(s)+1));
            strcpy(WinData.argv[WinData.argc], s);
            WinData.argc++;
           }
       }
    while (s != NULL);
   }

void Cleanup()
   {
    int i;

    // Free the command line holder memory
    if (WinData.argc > 0)
       {
        // Free in reverse order of allocation
        for (i = (WinData.argc-1); i >= 0; i--)
           {
            free(WinData.argv[i]);
           }
        // Free the parameter "pockets"
        free(WinData.argv);
       }
    // Free the memory that holds the video resolution list
    if (WinData.pResolutions)
        free(WinData.pResolutions);
   }

BOOL isdigits( char *s )
   {
    int i;

    for (i = 0; s[i]; i++)
       {
        if ((s[i] > '9') || (s[i] < '0'))
           {
            return FALSE;
           }
       }
    return TRUE;
   }

int FindNumParameter(char *s)
   {
    int i;

    for (i = 0; i < (WinData.argc-1); i++)
       {
        if (stricmp(WinData.argv[i], s) == 0)
           {
            if (isdigits(WinData.argv[i+1]) == TRUE)
               {
                return(atoi(WinData.argv[i+1]));
               }
            else
               {
                return -1;
               }
           }
       }
     return -1;
   }

BOOL FindParameter(char *s)
   {
    int i;

    for (i = 0; i < WinData.argc; i++)
       {
        if (stricmp(WinData.argv[i], s) == 0)
           {
            return TRUE;
           }
       }
    return FALSE;
   }

BOOL CreateMainWindow(int width, int height, int bpp, BOOL fullscreen)
   {
    HWND        hwnd;
    WNDCLASSEX  wndclass;
    DWORD       dwStyle, dwExStyle;
    int         x, y, sx, sy, ex, ey, ty;

    if ((hwnd = FindWindow(szAppName, szAppName)) != NULL)
       {
        SetForegroundWindow(hwnd);
        return 0;
       }

    wndclass.cbSize        = sizeof (wndclass);
    wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wndclass.lpfnWndProc   = (WNDPROC)WinData.wndproc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = WinData.hInstance;
    wndclass.hIcon         = 0;
    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
    wndclass.hbrBackground = (void *)COLOR_GRAYTEXT;
    wndclass.lpszMenuName  = NULL;
    wndclass.lpszClassName = szAppName;
    wndclass.hIconSm       = 0;


    if (!RegisterClassEx (&wndclass))
       {
        MessageBox(NULL, "Window class registration failed.", "FATAL ERROR", MB_OK);
        return FALSE;
       }

    if (fullscreen)
       {
        dwExStyle = WS_EX_TOPMOST;
        dwStyle = WS_POPUP | WS_VISIBLE;
        x = y = 0;
        sx = WinData.width;
        sy = WinData.height;
       }
    else
       {
        dwExStyle = 0;
        //dwStyle = WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;  // Use this if you want a "normal" window
        dwStyle = WS_CAPTION;
        ex = GetSystemMetrics(SM_CXEDGE);
        ey = GetSystemMetrics(SM_CYEDGE);
        ty = GetSystemMetrics(SM_CYSIZE);
        // Center the window on the screen
        x = (DevInfo.width / 2) - ((WinData.width+(2*ex)) / 2);
        y = (DevInfo.height / 2) - ((WinData.height+(2*ey)+ty) / 2);
        sx = WinData.width+(2*ex);
        sy = WinData.height+(2*ey)+ty;
        /*
           Check to be sure the requested window size fits on the screen and
           adjust each dimension to fit if the requested size does not fit.
        */
        if (sx >= DevInfo.width)
           {
            x = 0;
            sx = DevInfo.width-(2*ex);
           }
        if (sy >= DevInfo.height)
           {
            y = 0;
            sy = DevInfo.height-((2*ey)+ty);
           }
       }

    if ((hwnd = CreateWindowEx (dwExStyle,
                    szAppName,               // window class name
		            "glDemo",                // window caption
                    dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // window style
                    x,           // initial x position
                    y,           // initial y position
                    sx,           // initial x size
                    sy,           // initial y size
                    NULL,                    // parent window handle
                    NULL,                    // window menu handle
                    WinData.hInstance,       // program instance handle
		            NULL))                   // creation parameters
                    == NULL)
        {
         ChangeDisplaySettings(0, 0);
         MessageBox(NULL, "Window creation failed.", "FATAL ERROR", MB_OK);
         return FALSE;
        }

    WinData.hWnd = hwnd;

    if (!InitOpenGL())
       {
        WinData.hWnd = NULL;
        return FALSE;
       }

    ShowWindow(WinData.hWnd, WinData.iCmdShow);
    UpdateWindow(WinData.hWnd);

    SetForegroundWindow(WinData.hWnd);
    SetFocus(WinData.hWnd);

    return TRUE;
   }


LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
   {
    switch (iMsg)
       {
        case WM_CHAR:
             switch(wParam)
                {
                 case VK_ESCAPE:
                      SendMessage(hwnd, WM_CLOSE, 0, 0);
                      break;
                }
             break;

        case WM_ACTIVATE:
             if ((LOWORD(wParam) != WA_INACTIVE) && ((HWND)lParam == NULL))
                {
                 ShowWindow(WinData.hWnd, SW_RESTORE);
                 SetForegroundWindow(WinData.hWnd);
                }
             else
                {
                 if (WinData.bFullScreen)
                    {
                     ShowWindow(WinData.hWnd, SW_MINIMIZE);
                    }
                }
             return 0;

        case WM_SIZE:
             if (WinData.hGLRC)
                {
                 // Redefine the viewing volume and viewport when the window size changes.
                 WinData.glnWidth = (GLsizei)LOWORD(lParam);
                 WinData.glnHeight = (GLsizei)HIWORD(lParam);
                 WinData.gldAspect = (float)((GLdouble)WinData.glnWidth/(GLdouble)WinData.glnHeight);
                 glViewport( 0, 0, WinData.glnWidth, WinData.glnHeight );
                }
             return 0;

        case WM_CLOSE:
             ShutdownOpenGL();
             WinData.bActive = FALSE;
             break;

        case WM_DESTROY:
             PostQuitMessage (0);
             return 0;
       }

    return DefWindowProc (hwnd, iMsg, wParam, lParam);
   }

// This function builds a list the screen resolutions supported by the display driver
void BuildModeList()
   {
    DEVMODE  dm;
    int      mode;

    mode = 0;
    while(EnumDisplaySettings(NULL, mode, &dm))
       {
        mode++;
       }

    WinData.pResolutions = (screen_res_t *)malloc(sizeof(screen_res_t)*mode);
    mode = 0;
    while(EnumDisplaySettings(NULL, mode, &dm))
       {
        WinData.pResolutions[mode].width = dm.dmPelsWidth;
        WinData.pResolutions[mode].height = dm.dmPelsHeight;
        WinData.pResolutions[mode].bpp = dm.dmBitsPerPel;
        WinData.pResolutions[mode].flags = dm.dmDisplayFlags;
        WinData.pResolutions[mode].frequency = dm.dmDisplayFrequency;
        mode++;
       }
    WinData.iResCount = mode;
   }

BOOL SetVideoMode()
   {
    OSVERSIONINFO   vinfo;
    int             mode;
    DEVMODE         dm;

    vinfo.dwOSVersionInfoSize = sizeof(vinfo);

    WinData.bChangeBPP = FALSE;

    if ( GetVersionEx( &vinfo) )
       {
        if ( vinfo.dwMajorVersion > 4 )
           {
            WinData.bChangeBPP = TRUE;
           }
        else
        if ( vinfo.dwMajorVersion == 4 )
           {
            if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
               {
                WinData.bChangeBPP = TRUE;
               }
            else
            if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
               {
                if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
                   {
                    WinData.bChangeBPP = TRUE;
                   }
               }
           }
       }
    else
       {
        MessageBox(NULL, "SetVideoMode - GetVersionEx failed\n", "FATAL ERROR", MB_OK);
        return FALSE;
       }

    if (WinData.bFullScreen)
       {
        if ((WinData.bpp    == DevInfo.bpp) &&
            (WinData.width  == DevInfo.width) &&
            (WinData.height == DevInfo.height))
           {
            WinData.iVidMode = 0;
            return TRUE;
           }
        if ((WinData.bChangeBPP == FALSE) && (DevInfo.bpp != WinData.bpp))
           {
            MessageBox(NULL, "This version of Windows cannot change color depth.\n"
                             "Please request different video mode settings or adjust\n"
                             "your desktop color depth.", "FATAL ERROR", MB_OK);
            return FALSE;
           }
        for (mode = 0; mode < WinData.iResCount; mode++)
           {
            if ((WinData.pResolutions[mode].width == WinData.width) &&
                (WinData.pResolutions[mode].height == WinData.height) &&
                (WinData.pResolutions[mode].bpp == WinData.bpp))
               {
                WinData.iVidMode = mode;

                memset(&dm, 0, sizeof(dm));
                dm.dmSize = sizeof(dm);

                dm.dmPelsWidth  = WinData.width;
                dm.dmPelsHeight = WinData.height;
                dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;

                if (WinData.bpp != DevInfo.bpp)
                   {
                    dm.dmBitsPerPel = WinData.bpp;
                    dm.dmFields |= DM_BITSPERPEL;
                   }

                if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
                   {
                    MessageBox(NULL, "SetVideoMode - ChangeDisplaySettings failed.\n"
                                     "Switching to windowed mode.", "WARNING", MB_OK);
                    WinData.bFullScreen = FALSE;
                    return TRUE;
                   }
                return TRUE;
               }
           }
        MessageBox(NULL, "Your requested video mode is unavailable.\n"
                         "Please request different video mode settings.", "FATAL ERROR", MB_OK);
        return FALSE;
       }
    else
       {
        if (DevInfo.bpp != WinData.bpp)
           {
            MessageBox(NULL, "Your requested color depth and desktop do not match.\n"
                             "Using your current desktop color depth.", "WARNING", MB_OK);
           }
       }
    return TRUE;
   }

BOOL InitOpenGL()
   {
    int     pfm;   // pixel format
    RECT    rect;

    PIXELFORMATDESCRIPTOR pfd = 
        {
         sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
                1,                       // version number
                PFD_DRAW_TO_WINDOW |     // support window
                PFD_SUPPORT_OPENGL |     // support OpenGL
                PFD_DOUBLEBUFFER,        // double buffered
                PFD_TYPE_RGBA,           // RGBA type
                24,                      // 24-bit color depth
                0, 0, 0, 0, 0, 0,        // color bits ignored
                0,                       // no alpha buffer
                0,                       // shift bit ignored
                0,                       // no accumulation buffer
                0, 0, 0, 0,              // accum bits ignored
                32,                      // 32-bit z-buffer      
                0,                       // no stencil buffer
                0,                       // no auxiliary buffer
                PFD_MAIN_PLANE,          // main layer
                0,                       // reserved
                0, 0, 0                  // layer masks ignored
        };
    if ((WinData.hDC = GetDC(WinData.hWnd)) == NULL)
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "GetDC on main window failed", "FATAL ERROR", MB_OK);
        return FALSE;
       }

    if ((pfm = ChoosePixelFormat(WinData.hDC, &pfd)) == 0)
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "ChoosePixelFormat failed\n", "FATAL ERROR", MB_OK);
        return FALSE;
       }
    if (SetPixelFormat(WinData.hDC, pfm, &pfd) == FALSE)
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "SetPixelFormat failed\n", "FATAL ERROR", MB_OK);
        return FALSE;
       }
    DescribePixelFormat(WinData.hDC, pfm, sizeof(pfd), &pfd);

    if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) // Incorrectly reported on most drivers I've tested
       {
        if (WinData.bAllowSoft == FALSE)
           {
            ChangeDisplaySettings(0, 0);
            MessageBox(NULL, "OpenGL Driver is not accelerated\n", "FATAL ERROR", MB_OK);
            return FALSE;
           }
       }

    if ((WinData.hGLRC = wglCreateContext(WinData.hDC)) == 0)
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "wglCreateContext failed\n", "FATAL ERROR", MB_OK);
        goto fail;
       }

    if (!wglMakeCurrent(WinData.hDC, WinData.hGLRC))
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "wglMakeCurrent failed\n", "FATAL ERROR", MB_OK);
        goto fail;
       }

    GetClientRect(WinData.hWnd, &rect);
    WinData.glnWidth= rect.right;
    WinData.glnHeight = rect.bottom;
    WinData.gldAspect = (float)((GLdouble)WinData.glnWidth/(GLdouble)WinData.glnHeight);

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_POLYGON_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );

    return TRUE;

fail:
    if ( WinData.hGLRC )
       {
        wglDeleteContext( WinData.hGLRC);
        WinData.hGLRC = NULL;
       }

    if ( WinData.hDC )
       {
        ReleaseDC(WinData.hWnd, WinData.hDC);
        WinData.hDC = NULL;
       }
    return FALSE;
   }

    
void ShutdownOpenGL(void)
   {
    if (WinData.hGLRC)
       {
        if ((!wglMakeCurrent(NULL, NULL)) && (!WinData.bFullScreen))
           {
            MessageBox(NULL, "ShutdownOpenGL - wglMakeCurrent failed\n", "ERROR", MB_OK);
           }
        if (!wglDeleteContext(WinData.hGLRC))
           {
            MessageBox(NULL, "ShutdownOpenGL - wglDeleteContext failed\n", "ERROR", MB_OK);
           }
        WinData.hGLRC = NULL;
       }
    if (WinData.hDC)
       {
        if (!ReleaseDC(WinData.hWnd, WinData.hDC))
           {
            MessageBox(NULL, "ShutdownOpenGL - ReleaseDC failed\n", "ERROR", MB_OK);
           }
        WinData.hDC   = NULL;
       }
    if (WinData.bFullScreen)
       {
        ChangeDisplaySettings( 0, 0 );
       }
   }

// Render your scenes through this function
void RenderScene()
   {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // set up a projection matrix to fill the client window
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glPushMatrix();

    glDisable(GL_TEXTURE_2D);
    glColor4f( 0.5f, 0.5f, 0.5f, 1.0f );
    glBindTexture(GL_TEXTURE_2D, 0);
    glBegin(GL_QUADS);
      glVertex3f( -512.0f,-32.0f,-512.0f);
      glVertex3f( -512.0f,-32.0f, 512.0f);
      glVertex3f(  512.0f,-32.0f, 512.0f);
      glVertex3f(  512.0f,-32.0f,-512.0f);
    glEnd();

    glTranslatef( 0.0f, 0.0f, -128.0f );
    fAngle += 2.0f;
    if (fAngle >= 360.0f)
       fAngle = 0.0f;
    glRotatef( fAngle, 0.0f, 1.0f, 0.0f );

    glEnable(GL_TEXTURE_2D);
    glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
    glBindTexture(GL_TEXTURE_2D, Texture);
    glBegin(GL_TRIANGLES);
      glTexCoord2f( 0.0f, 5.0f);
      glVertex3f(  0.0f, 32.0f, 0.0f);
      glTexCoord2f( 0.0f, 0.0f);
      glVertex3f(-32.0f,-32.0f, 0.0f);
      glTexCoord2f( 4.0f, 0.0f);
      glVertex3f( 32.0f,-32.0f, 0.0f);
    glEnd();

    glPopMatrix();


    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    gluPerspective(WinData.fov, WinData.gldAspect, WinData.NearClip, WinData.FarClip);

    if (!SwapBuffers(WinData.hDC))
       {
        ChangeDisplaySettings(0, 0);
        MessageBox(NULL, "RenderScene - SwapBuffers failed!\n", "FATAL ERROR", MB_OK);
        SendMessage(WinData.hWnd, WM_CLOSE, 0, 0);
       }
   }

/*
  This function is quick and dirty and is meant to be illustrative only.
  If the texture loading fails, your triangle will be rendered in white
  with no texture.  Or, depending on the contents of the texture.raw
  file, may look rather bizarre.
*/
void LoadTexture()
   {
    int            fn, readin;
    unsigned char *rawbuff;

    rawbuff = (unsigned char *)malloc(64*64*3);
    if ((fn = open("texture.raw", O_RDONLY | O_BINARY )) == -1)
       { // Error opening texture file
        Texture = 0;
        return;
       }
    readin = read(fn, rawbuff, 64*64*3);
    close(fn);
    if (readin != (64*64*3))
       { // Error reading texture file
        Texture = 0;
        return;
       }

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    //glGenTextures(1, &Texture);
    Texture = 1;
    glBindTexture(GL_TEXTURE_2D, Texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, 3, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, rawbuff);
    glBindTexture(GL_TEXTURE_2D, 0);

    free(rawbuff);
   }

/*
  An alternative to the message boxes is the use of a console screen which you can spawn
  and use as a standard out display device.  I didn't bother with it. All you need to do
  is call AllocConsole and you will have a standard console.  Dont confuse this with the
  console that id Software invented with Quake, though.  It's not the same thing.  It's
  just a Win32 console you can use to display messages to with printf.

  HANDLE      conout;
  int         conwrite;

  AllocConsole();
  conout = GetStdHandle(STD_OUTPUT_HANDLE);
  WriteConsole(conout, "This is a test...\n", 18, &conwrite, NULL);
  FreeConsole();

  Better yet, create your own graphical console.

*/