outdated: 21.Lines, Antialiasing, Timing, Ortho View And Simple Sounds

这是一个简单的小游戏,类型相当于amidar,不过也有1000行,手困眼花......UP\DOWN\LEFT\RIGHT控制,SPACE重新开始。

在TimerInit()函数中,QueryPerformanceFrequency()函数查询性能计数器的频率。QueryPerformanceCounter()函数查询性能计数器的当前值。两个函数的参数都用到了LARGE_INTEGER的强制转换。以前写过一篇介绍的文章

在glPrint()函数里,新添了glScalef()函数(用缩放矩阵乘以当前矩阵),此处用来扩大字体矩阵的宽和高。glOrtho()函数(用投影矩阵乘以当前矩阵),此处用来创建一个680X480矩阵。

enmey对于player的追踪,代码如下。

 1 if ((enemy[loop1].x < player.x) && (enemy[loop1].fy == enemy[loop1].y * 40)) {
 2     enemy[loop1].x++;                 // Move the enemy right
 3 }
 4 if ((enemy[loop1].x > player.x) && (enemy[loop1].fy == enemy[loop1].y * 40)) {
 5     enemy[loop1].x--;                 // Move the enemy left
 6 }
 7 if ((enemy[loop1].y < player.y) && (enemy[loop1].fx == enemy[loop1].x * 60)) {
 8     enemy[loop1].y++;                 // Move the enemy down
 9 }
10 if ((enemy[loop1].y > player.y) && (enemy[loop1].fx == enemy[loop1].x * 60)) {
11     enemy[loop1].y--;                 // Move the enemy up
12 }

enemy每次走一个像素点,player在y轴上走每次40个像素点,在x轴上每次走60个像素点。按照每个方块的边角值fx、fy(游戏窗口的大小)来判定是否相等,如果过按照x、y来判定是否相遇,那enemy就吃炫迈了。

代码如下,同样修改部分位于双行星号内,但基本是重写了一遍。

   1 #include <windows.h>
   2 #include <stdio.h>
   3 #include <math.h>
   4 #include <gl/glew.h>
   5 #include <gl/glut.h>
   6 #include <GL/GLUAX.H>
   7 #pragma comment(lib, "legacy_stdio_definitions.lib")
   8 /*
   9  *  Every OpenGL program is linked to a Rendering Context.
  10  *  A Rendering Context is what links OpenGL calls to the Device Context.
  11  *  In order for your program to draw to a Window you need to create a Device Context.
  12  *  The DC connects the Window to the GDI (Graphics Device Interface).
  13  */
  14 
  15 HGLRC     hRC = NULL;         // Permanent rendering context
  16 HDC       hDC = NULL;         // Private GDI device context
  17 HWND      hWnd = NULL;        // Holds our window handle
  18 HINSTANCE hInstance;          // Holds the instance of the application
  19 
  20 /*
  21  *  It's important to make this global so that each procedure knows if 
  22  *  the program is running in fullscreen mode or not.
  23  */
  24 
  25 bool keys[256];         // Array used for the keyboard routine
  26 bool active = TRUE;     // Window active flag set to TRUE by default
  27 bool fullscreen = TRUE; // Fullscreen flag set to fullscreen mode by default
  28 
  29 /******************************************************************************************************************************************/
  30 /******************************************************************************************************************************************/
  31 bool vline[11][10];                 // Verticle lines
  32 bool hline[10][11];                 // Horizontal lines
  33 bool ap;                            // 'A' key press
  34 bool filled;                        // Done filling in the grid
  35 bool gameover;
  36 bool anti = TRUE;                   // Antialiasing
  37 
  38 int loop1;
  39 int loop2;
  40 int delay;                          // Enemy delay
  41 int adjust = 3;                     // Speed adjustment for really slow video cards
  42 int lives = 5;                      // Player lives
  43 int level = 1;                      // Internal game level
  44 int level2 = level;                 // Display game level
  45 int stage = 1;                      // Game stage
  46 
  47 struct object {                     // Player
  48     int fx, fy;                     // Fine Movement position
  49     int x, y;                       // Current player position
  50     float spin;                     // Spin direction
  51 };
  52 struct object player;
  53 struct object enemy[9];
  54 struct object hourglass;
  55 
  56 struct {                                      // Timer information
  57     __int64 frequency;
  58     float resolution;
  59     unsigned long mm_timer_start;             // Multimedia timer start value
  60     unsigned long mm_timer_elapsed;           // Multimedia timer elspsed time
  61     bool performance_timer;                   // Using the performance timer ?
  62     __int64 performance_timer_start;          // Performance timer start value
  63     __int64 performance_timer_elapsed;        // Performance timer elspsed value
  64 } timer;
  65 
  66 int steps[6] = { 1, 2, 4, 5, 10, 20 };        // Stepping values for slow video adjustment
  67 
  68 GLuint texture[2];                   // Font texture storage space
  69 GLuint base;                         // Base display list for the font
  70 
  71 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc
  72 
  73 void TimerInit(void)                                  // Initialize timer
  74 {
  75     memset(&timer, 0, sizeof(timer));
  76     // Check to see if a performance counter is available
  77     // If one is available the timer frequency will be updated
  78     if (!QueryPerformanceFrequency((LARGE_INTEGER *)&timer.frequency)) {
  79         // No performance counter available
  80         timer.performance_timer = FALSE;
  81         timer.mm_timer_start = timeGetTime();            // To get current time
  82         timer.resolution = 1.0f / 1000.0f;
  83         timer.frequency = 1000;
  84         timer.mm_timer_elapsed = timer.mm_timer_start;
  85     }
  86     else {
  87         // Performance counter is available, use it instead of the multimedia timer
  88         // Get the current time and store it in performance_timer_start
  89         QueryPerformanceCounter((LARGE_INTEGER *)&timer.performance_timer_start);
  90         timer.performance_timer = TRUE;
  91         timer.resolution = (float)(((double)1.0f) / ((double)timer.frequency));
  92         timer.performance_timer_elapsed = timer.performance_timer_start;
  93     }
  94 }
  95 
  96 float TimerGetTime()                      // Get time in milliseconds
  97 {
  98     __int64 time;
  99 
 100     if (timer.performance_timer) {
 101         QueryPerformanceCounter((LARGE_INTEGER *)&time);
 102         return ((float)(time - timer.performance_timer_start) * timer.resolution) * 1000.0f;
 103     }
 104     else {
 105         return ((float)(timeGetTime() - timer.mm_timer_start) * timer.resolution) * 1000.0f;
 106     }
 107 }
 108 
 109 void ResetObjects(void)                      // Reset player and enemies
 110 {
 111     player.x = 0;
 112     player.y = 0;
 113     player.fx = 0;
 114     player.fy = 0;
 115 
 116     for (loop1 = 0; loop1 < (stage * level); ++loop1) {
 117         enemy[loop1].x = 5 + rand() % 6;
 118         enemy[loop1].y = rand() % 11;
 119         enemy[loop1].fx = enemy[loop1].x * 60;
 120         enemy[loop1].fy = enemy[loop1].y * 40;
 121     }
 122 }
 123 
 124 AUX_RGBImageRec* LoadBMP(char* Filename)
 125 {
 126     FILE* File = NULL;
 127     
 128     if (!Filename) {
 129         return NULL;
 130     }
 131 
 132     File = fopen(Filename, "r");
 133     if (File) {
 134         fclose(File);
 135         return auxDIBImageLoad(Filename);
 136     }
 137 
 138     return NULL;
 139 }
 140 
 141 int LoadGLTextures()
 142 {
 143     int Status = FALSE;
 144 
 145     AUX_RGBImageRec* TextureImage[2];
 146     
 147     memset(TextureImage, 0, sizeof(void*) * 2);
 148 
 149     if ((TextureImage[0] = LoadBMP("Font.bmp")) &&
 150         (TextureImage[1] = LoadBMP("Image.bmp")))
 151     {
 152         Status = TRUE;
 153         glGenTextures(2, &texture[0]);
 154 
 155         for (loop1 = 0; loop1 < 2; ++loop1) {
 156             glBindTexture(GL_TEXTURE_2D, texture[loop1]);
 157             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 158             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 159             glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop1]->sizeX, TextureImage[loop1]->sizeY,
 160                 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop1]->data);
 161         }
 162     }
 163 
 164     for (loop1 = 0; loop1 < 2; ++loop1) {
 165         if (TextureImage[loop1]) {
 166             if (TextureImage[loop1]->data) {
 167                 free(TextureImage[loop1]->data);
 168             }
 169             free(TextureImage[loop1]);
 170         }
 171     }
 172     return Status;
 173 }
 174 
 175 GLvoid BuildFont(GLvoid)
 176 {
 177     base = glGenLists(256);
 178     glBindTexture(GL_TEXTURE_2D, texture[0]);
 179     for (loop1 = 0; loop1 < 256; ++loop1) {
 180         float cx = float(loop1 % 16) / 16.0f;                        // X position of current character
 181         float cy = float(loop1 / 16) / 16.0f;                        // Y position of current character
 182 
 183         glNewList(base + loop1, GL_COMPILE);
 184             glBegin(GL_QUADS);
 185                 glTexCoord2f(cx, 1.0f - cy - 0.0625f);               // Bottom left
 186                 glVertex2d(0, 16);
 187                 glTexCoord2f(cx + 0.0625f, 1.0f - cy - 0.0625f);     // Bottom right
 188                 glVertex2d(16, 16);
 189                 glTexCoord2f(cx + 0.0625f, 1.0f - cy);               // Top right
 190                 glVertex2d(16, 0);
 191                 glTexCoord2f(cx, 1.0f - cy);                         // Top left
 192                 glVertex2d(0, 0);
 193             glEnd();
 194             glTranslated(15, 0, 0);
 195         glEndList();
 196     }
 197 }
 198 
 199 GLvoid KillFont(GLvoid)
 200 {
 201     glDeleteLists(base, 256);
 202 }
 203 
 204 GLvoid glPrint(GLint x, GLint y, int set, const char* fmt, ...)
 205 {
 206     char text[256];
 207     va_list ap;                             // Pointer to listof arguments
 208 
 209     if (fmt == NULL) {
 210         return;
 211     }
 212 
 213     va_start(ap, fmt);                      // Parses the string for variables
 214         vsprintf(text, fmt, ap);            // And converts symbols ot actual numbers
 215     va_end(ap);                             // Results are stoed in text
 216 
 217     if (set > 1) {                          // Did user choose an invalid character set
 218         set = 1;
 219     }
 220     glEnable(GL_TEXTURE_2D);
 221     glLoadIdentity();
 222     glTranslated(x, y, 0);                  // Position the text (0, 0, -Bottom left)
 223     glListBase(base - 32 + (128 * set));    // Choose the font set (0 or 1)
 224 
 225     if (set == 0) {
 226         glScalef(1.5f, 2.0f, 1.0f);         // Enlarge font width and height
 227     }
 228     glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);    // Write the text to the screen
 229     glDisable(GL_TEXTURE_2D);
 230 }
 231 
 232 GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   // Resize and initialize the GL window
 233 {
 234     if (height == 0) {                                // Prevent a divide by zero by
 235         height = 1;                                   // Making height equal one
 236     }
 237     
 238     glViewport(0, 0, width, height);                  // Reset the current viewport
 239 
 240     /*
 241      *  The following lines set the screen up for a perspective view. 
 242      *  Meaning things in the distance get smaller. This creates a realistic looking scene. 
 243      *  The perspective is calculated with a 45 degree viewing angle based on 
 244      *  the windows width and height. The 0.1f, 100.0f is the starting point and 
 245      *  ending point for how deep we can draw into the screen.
 246      *
 247      *  The projection matrix is responsible for adding perspective to our scene.
 248      *  glLoadIdentity() restores the selected matrix to it's original state.
 249      *  The modelview matrix is where our object information is stored.
 250      *   Lastly we reset the modelview matrix.
 251      */
 252 
 253     glMatrixMode(GL_PROJECTION);                      // Select the projection matrix
 254     glLoadIdentity();                                 // Reset the projection matrix
 255     
 256                                                       // Calculate the aspect ratio of the window
 257     //gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
 258     glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);  // Create orhto 640X480 view (0, 0, at the top)
 259 
 260     glMatrixMode(GL_MODELVIEW);                       // Seclet the modelview matrix
 261     glLoadIdentity();                                 // Reset the modelview matrix
 262 }
 263 
 264 int InitGL(GLvoid)                                    // All setup for OpenGL goes here
 265 {
 266     /*
 267      *  Smooth shading blends colors nicely across a polygon, and smoothes out lighting.
 268      */
 269 
 270     if (!LoadGLTextures()) {
 271         return FALSE;
 272     }
 273     BuildFont();
 274 
 275     glShadeModel(GL_SMOOTH);                          // Enables smooth shading
 276     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);             // Black background
 277 
 278     glClearDepth(1.0f);                               // Depth buffer setup
 279 
 280     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);           // Set line antialiasing
 281     glEnable(GL_BLEND);
 282     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 283 
 284     return TRUE;
 285 }
 286 
 287 /*
 288  *  For now all we will do is clear the screen to the color we previously decided on,
 289  *  clear the depth buffer and reset the scene. We wont draw anything yet.
 290  */
 291 int DrawGLScene(GLvoid)                                  // Here's where we do all the drawing
 292 {
 293     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Clear the screen and the depth buffer
 294     glBindTexture(GL_TEXTURE_2D, texture[0]);
 295 
 296     glColor3f(1.0f, 0.5f, 1.0f);                         // Set color to purple
 297     glPrint(207, 24, 0, "GRID CRAZY");
 298     glColor3f(1.0f, 1.0f, 0.0f);
 299     glPrint(20, 20, 1, "Level:%2i", level2);             // Write actual level stats
 300     glPrint(20, 40, 1, "Stage:2%i", stage);              // Write stage stats
 301 
 302     if (gameover) {
 303         glColor3ub(rand() % 255, rand() % 255, rand() % 255);    // Pick A random color
 304         glPrint(456, 20, 1, "GAME  OVER");
 305         glPrint(456, 35, 1, "PRESS SPACE");
 306     }
 307 
 308     for (loop1 = 0; loop1 < lives - 1; ++loop1) {                 // Draw liver counter
 309         glLoadIdentity();
 310         glTranslatef(490 + (loop1 * 40.0f), 40.0f, 0.0f);         // Move to the right of our title text
 311         glRotatef(-player.spin, 0.0f, 0.0f, 1.0f);                // Rotate counter clockwise
 312         glColor3f(0.0f, 1.0f, 0.0f);                              // Light green
 313         glBegin(GL_LINES);                                        // Start drawing our player using lines
 314             glVertex2d(-5, -5);
 315             glVertex2d(5, 5);
 316             glVertex2d(5, -5);
 317             glVertex2d(-5, 5);
 318         glEnd();
 319 
 320         glRotatef(-player.spin * 0.5f, 0.0f, 0.0f, 1.0f);
 321         glColor3f(0.0f, 0.75f, 0.0f);                             // Dark green
 322         glBegin(GL_LINES);                                        // Start drawing our player using lines
 323             glVertex2d(-7, 0);
 324             glVertex2d(7, 0);
 325             glVertex2d(0, -7);
 326             glVertex2d(0, 7);
 327         glEnd();
 328     }
 329 
 330     filled = TRUE;                                       // Set filled to true before testing
 331     glLineWidth(1.0f);                                   // Set line width for celld to 2.0f
 332     glDisable(GL_LINE_SMOOTH);                           // Disable antialiasing
 333     glLoadIdentity();
 334     for (loop1 = 0; loop1 < 11; ++loop1) {               // Left to right
 335         for (loop2 = 0; loop2 < 11; ++loop2) {           // Top to bottom
 336             glColor3f(0.0f, 0.5f, 1.0f);
 337             if (hline[loop1][loop2]) {                   // Has the horizontal line been traced
 338                 glColor3f(1.0f, 1.0f, 1.0f);
 339             }
 340             if (loop1 < 10) {                            // Don't draw to far right
 341                 if (!hline[loop1][loop2]) {              // If a horizontal line isn't filled
 342                     filled = FALSE;
 343                 }
 344                 glBegin(GL_LINES);                       // Start drwaing horizontal cell borders
 345                     glVertex2d(20 + (loop1 * 60), 70 + (loop2 * 40));
 346                     glVertex2d(80 + (loop1 * 60), 70 + (loop2 * 40));
 347                 glEnd();
 348             }
 349             glColor3f(0.0f, 0.5f, 1.0f);
 350             if (vline[loop1][loop2]) {                   // Has the horizontal line been trace
 351                 glColor3f(1.0f, 1.0f, 1.0f);
 352             }
 353             if (loop2 < 10) {
 354                 if (!vline[loop1][loop2]) {              // If a verticle line isn't filled
 355                     filled = FALSE;
 356                 }
 357                 glBegin(GL_LINES);                       // Start drwaing verticle cell borders
 358                     glVertex2d(20 + (loop1 * 60), 70 + (loop2 * 40));
 359                     glVertex2d(20 + (loop1 * 60), 110 + (loop2 * 40));
 360                 glEnd();
 361             }
 362             glEnable(GL_TEXTURE_2D);
 363             glColor3f(1.0f, 1.0f, 1.0f);
 364             glBindTexture(GL_TEXTURE_2D, texture[1]);
 365             if ((loop1 < 10) && (loop2 < 10)) {           // If in bounds, fill in traced boxes
 366                 if (hline[loop1][loop2] && hline[loop1][loop2 + 1] && 
 367                     vline[loop1][loop2] && vline[loop1 + 1][loop2])
 368                 {
 369                     glBegin(GL_QUADS);
 370                         glTexCoord2f(float(loop1 / 10.0f) + 0.1f, 1.0f - (float(loop2 / 10.0f)));
 371                         glVertex2d(20 + (loop1 * 60) + 59, (70 + loop2 * 40 + 1));   // Top right
 372                         glTexCoord2f(float(loop1 / 10.0f), 1.0f - (float(loop2 / 10.0f)));
 373                         glVertex2d(20 + (loop1 * 60) + 1, (70 + loop2 * 40 + 1));   // Top left
 374                         glTexCoord2f(float(loop1 / 10.0f), 1.0f - (float(loop2 / 10.0f) + 0.1f));
 375                         glVertex2d(20 + (loop1 * 60) + 1, (70 + loop2 * 40 + 39));   // Botttom left
 376                         glTexCoord2f(float(loop1 / 10.0f) + 0.1f, 1.0f - (float(loop2 / 10.0f) + 0.1f));
 377                         glVertex2d(20 + (loop1 * 60) + 59, (70 + loop2 * 40 + 39));   // Bottom right
 378                     glEnd();
 379                 }
 380             }
 381             glDisable(GL_TEXTURE_2D);
 382         }    
 383     }
 384     glLineWidth(1.0f);
 385 
 386     if (anti) {
 387         glEnable(GL_LINE_SMOOTH);                         // Enable antialiasing
 388     }
 389 
 390     if (hourglass.fx == 1) {
 391         glLoadIdentity();
 392         glTranslatef(20.0f + (hourglass.x * 60), 70.0f + (hourglass.y * 40), 0.0f);
 393         glRotatef(hourglass.spin, 0.0f, 0.0f, 1.0f);
 394         glColor3ub(rand() % 255, rand() % 255, rand() % 255);
 395         glBegin(GL_LINES);                                 // Hourglass
 396             glVertex2d(-5, -5);
 397             glVertex2d(5, 5);
 398             glVertex2d(5, -5);
 399             glVertex2d(-5, 5);
 400             glVertex2d(-5, 5);
 401             glVertex2d(5, 5);
 402             glVertex2d(-5, -5);
 403             glVertex2d(5, -5);
 404         glEnd();
 405     }
 406 
 407     glLoadIdentity();
 408     glTranslatef(player.fx + 20.0f, player.fy + 70.0f, 0.0f);     // Player
 409     glRotatef(player.spin, 0.0f, 0.0f, 1.0f);
 410     glColor3f(0.0f, 1.0f, 0.0f);
 411     glBegin(GL_LINES);                           // Player using lines
 412         glVertex2d(-5, -5);
 413         glVertex2d(5, 5);
 414         glVertex2d(5, -5);
 415         glVertex2d(-5, 5);
 416     glEnd();
 417 
 418     glRotatef(player.spin * 0.5f, 0.0f, 0.0f, 1.0f);
 419     glColor3f(0.0f, 0.75f, 0.0f);
 420     glBegin(GL_LINES);                           // Player using lines
 421         glVertex2d(-7, 0);
 422         glVertex2d(7, 0);
 423         glVertex2d(0, -7);
 424         glVertex2d(0, 7);
 425     glEnd();
 426 
 427     for (loop1 = 0; loop1 < (stage * level); ++loop1) {             // Enemies
 428         glLoadIdentity();
 429         glTranslatef(enemy[loop1].fx + 20.0f, enemy[loop1].fy + 70.0f, 0.0f);
 430         glColor3f(1.0f, 0.5f, 0.5f);                     // Pink
 431         glBegin(GL_LINES);
 432             glVertex2d(0, -7);
 433             glVertex2d(-7, 0);
 434             glVertex2d(-7, 0);
 435             glVertex2d(0, 7);
 436             glVertex2d(0, 7);
 437             glVertex2d(7, 0);
 438             glVertex2d(7, 0);
 439             glVertex2d(0, -7);
 440         glEnd();
 441 
 442         glRotatef(enemy[loop1].spin, 0.0f, 0.0f, 1.0f);
 443         glColor3f(1.0f, 0.0f, 0.0f);
 444         glBegin(GL_LINES);
 445             glVertex2d(-7, -7);
 446             glVertex2d(7, 7);
 447             glVertex2d(-7, 7);
 448             glVertex2d(7, -7);
 449         glEnd();
 450     }
 451     return TRUE;                                         // everthing went OK
 452 }
 453 /******************************************************************************************************************************************/
 454 /******************************************************************************************************************************************/
 455 /*
 456  *  The job of KillGLWindow() is to release the Rendering Context, 
 457  *  the Device Context and finally the Window Handle. 
 458  */
 459 
 460 GLvoid KillGLWindow(GLvoid)                              // Properly kill the window
 461 {
 462     if (fullscreen) {                                    // Are we in fullscreen mode
 463         
 464         /*
 465          *  We use ChangeDisplaySettings(NULL,0) to return us to our original desktop.
 466          *  After we've switched back to the desktop we make the cursor visible again.
 467          */
 468 
 469         ChangeDisplaySettings(NULL, 0);                  // if so switch back to the desktop
 470         ShowCursor(TRUE);                                // Show mouse pointer
 471     }
 472 
 473     if (hRC) {                                           // Do we have a rendering context
 474         if (!wglMakeCurrent(NULL, NULL)) {                // Are we able to release the DC and RC contexts
 475             MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 476         }
 477 
 478         if (!wglDeleteContext(hRC)) {                     // Are we able to delete the RC
 479             MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 480             hRC = NULL;                                  // Set RC to NULL
 481         }
 482 
 483         if (hDC && !ReleaseDC(hWnd, hDC)) {              // Are we able to release the DC
 484             MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 485             hDC = NULL;                                  // Set DC to NULL
 486         }
 487         if (hWnd && !DestroyWindow(hWnd)) {              // Are we able to destroy the window
 488             MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 489             hWnd = NULL;                                 // Set hWnd to NULL
 490         }
 491 
 492         if (!UnregisterClass("OpenGL", hInstance)) {     // Are we able to unregister class
 493             MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 494             hInstance = NULL;                            // Set hInstance to NULL
 495         }
 496     }
 497 /******************************************************************************************************************************************/
 498 /******************************************************************************************************************************************/
 499     KillFont();
 500 /******************************************************************************************************************************************/
 501 /******************************************************************************************************************************************/
 502 }
 503 
 504 /*
 505  * The next section of code creates our OpenGL Window.
 506  */
 507 
 508 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
 509 {
 510     /*
 511      * Find  a pixel format that matches the one we want
 512      */
 513     GLuint PixelFormat;                                  // Holds the result after serching for a match
 514     
 515     /*
 516      * Before you create a window, you MUST register a Class for the window
 517      */
 518     WNDCLASS wc;                                         // Windows class structure
 519 
 520     /*
 521      *  dwExStyle and dwStyle will store the Extended and normal Window Style Information.
 522     */
 523     DWORD dwExStyle;                                     // Window extend style
 524     DWORD dwStyle;                                       // Window style
 525 
 526     RECT WindowRect;                                     // Grabs rectangle upper left/lower right values
 527     WindowRect.left = (long)0;                           // Set left value to 0
 528     WindowRect.right = (long)width;                      // Set right value to requested width
 529     WindowRect.top = (long)0;                            // Set top value to 0
 530     WindowRect.bottom = (long)height;                    // Set bottom value to requested height
 531 
 532     fullscreen = fullscreenflag;                         // Set the global fullscreen flag
 533 
 534     /*
 535      *  The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized. 
 536      *  CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications. 
 537      *  WndProc is the procedure that watches for messages in our program. 
 538      *  No extra Window data is used so we zero the two fields. Then we set the instance. 
 539      *  Next we set hIcon to NULL meaning we don't want an ICON in the Window, 
 540      *  and for a mouse pointer we use the standard arrow. The background color doesn't matter 
 541      *  (we set that in GL). We don't want a menu in this Window so we set it to NULL, 
 542      *  and the class name can be any name you want. I'll use "OpenGL" for simplicity.
 543      */
 544     hInstance = GetModuleHandle(NULL);                   // Grab an instance for our window
 545     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;       // Redraw on move, and own DC for window
 546     wc.lpfnWndProc = (WNDPROC)WndProc;                   // WndProc handles message
 547     wc.cbClsExtra = 0;                                   // No extra window date
 548     wc.cbWndExtra = 0;                                   // No extra window date
 549     wc.hInstance = hInstance;                            // set the instance
 550     wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);              // Load the default icon
 551     wc.hCursor = LoadCursor(NULL, IDC_ARROW);            // Load the arrow pointer
 552     wc.hbrBackground = NULL;                             // No background requried for GL
 553     wc.lpszMenuName = NULL;                              // We don't want a menu
 554     wc.lpszClassName = "OpenGL";                         // set the class name
 555 
 556     if (!RegisterClass(&wc)) {                           // Attempt to register the window class
 557         MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 558         return FALSE;                                    // Exit and return false
 559     }
 560 
 561     if (fullscreen) {                                    // attempt fullsreen model
 562         
 563         /*
 564         T*  here are a few very important things you should keep in mind when switching to full screen mode.
 565          *  Make sure the width and height that you use in fullscreen mode is the same as 
 566          *  the width and height you plan to use for your window, and most importantly,
 567          *  set fullscreen mode BEFORE you create your window.
 568          */
 569         DEVMODE dmScreenSettings;                        // Device mode
 570         memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared
 571         dmScreenSettings.dmSize = sizeof(dmScreenSettings);     // Size of devmode structure
 572         dmScreenSettings.dmPelsWidth = width;            // Select window width
 573         dmScreenSettings.dmPelsHeight = height;          // Select window height
 574         dmScreenSettings.dmBitsPerPel = bits;            // Select bits per pixel
 575         dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
 576         
 577         /*
 578          *  In the line below ChangeDisplaySettings tries to switch to a mode that matches 
 579          *  what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes, 
 580          *  because it's supposed to remove the start bar at the bottom of the screen, 
 581          *  plus it doesn't move or resize the windows on your desktop when you switch to 
 582          *  fullscreen mode and back.
 583          */
 584         //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar
 585         if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
 586             //If the mode fails, offer two options. Quit or run in a window
 587             if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use"
 588                 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
 589             {
 590                 fullscreen = FALSE;                       // Select windowed mode (fullscreen=FLASE)
 591             }
 592             else {
 593                 // Pop up a message box letting user know the programe is closing.
 594                 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP);
 595                 return FALSE;                             // Exit and return FALSE
 596             }
 597         }
 598     }
 599 
 600     if (fullscreen) {                                     // Are we still in fullscreen mode
 601         
 602         /*
 603          *  If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW, 
 604          *  which force a top level window down to the taskbar once our window is visible. 
 605          *  For the window style we'll create a WS_POPUP window. 
 606          *  This type of window has no border around it, making it perfect for fullscreen mode.
 607 
 608          *  Finally, we disable the mouse pointer. If your program is not interactive, 
 609          *  it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though.
 610          */
 611         dwExStyle = WS_EX_APPWINDOW;                      // Window extended style
 612         dwStyle = WS_POPUP;                               // Window style
 613         ShowCursor(FALSE);                                // Hide mosue pointer 
 614     }
 615     else {
 616 
 617         /*
 618          *  If we're using a window instead of fullscreen mode, 
 619          *  we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. 
 620          *  For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. 
 621          *  WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, 
 622          *  window menu, and minimize / maximize buttons.
 623          */
 624         dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window extended style
 625         dwStyle = WS_OVERLAPPEDWINDOW;                    // Window style
 626     }
 627 
 628     /*
 629      *  By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders, 
 630      *  instead, the window will be made larger to account for the pixels needed to draw the window border. 
 631      *  In fullscreen mode, this command has no effect.
 632      */
 633     AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // Adjust window to true resqusted
 634     
 635     /*
 636      *  WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. 
 637      *  These styles prevent other windows from drawing over or into our OpenGL Window.
 638      */
 639     if (!(hWnd = CreateWindowEx(dwExStyle,                // Extended style for the window
 640         "OpenGL",                                         // Class name
 641         title,                                            // Window title
 642         WS_CLIPSIBLINGS |                                 // Requried window style
 643         WS_CLIPCHILDREN |                                 // Requried window style
 644         dwStyle,                                          // Select window style
 645         0, 0,                                             // Window position
 646         WindowRect.right - WindowRect.left,               // Calculate adjusted window width
 647         WindowRect.bottom - WindowRect.top,               // Calculate adjusted window height
 648         NULL,                                             // No parent window
 649         NULL,                                             // No menu
 650         hInstance,                                        // Instance
 651         NULL)))                                           // Don't pass anything to WM_CREATE
 652     {
 653         KillGLWindow();                                   //Reset the display
 654         MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 655         return FALSE;                                     // Retrurn FALSE;
 656     }
 657 
 658     /*
 659      *  aside from the stencil buffer and the (slow) accumulation buffer
 660      */
 661     static PIXELFORMATDESCRIPTOR pfd =                    // pfd tells windows how we want things to be 
 662     {
 663         sizeof(PIXELFORMATDESCRIPTOR),                    // Size of this pixel format descriptor
 664         1,                                                // Version number
 665         PFD_DRAW_TO_WINDOW |                              // Format must support window
 666         PFD_SUPPORT_OPENGL |                              // Format must support OpenGL
 667         PFD_DOUBLEBUFFER,                                 // Must support double buffer
 668         PFD_TYPE_RGBA,                                    // Request an RGBA format
 669         bits,                                             // Select our color depth
 670         0, 0, 0, 0, 0, 0,                                 // Color bits ignored
 671         0,                                                // No alpha buffer
 672         0,                                                // shift bit ignored
 673         0,                                                // No accumulation buffer
 674         0, 0, 0, 0,                                       // Accumulation bits ignored
 675         16,                                               // 16Bits Z_Buffer (depth buffer)
 676         0,                                                // No stencil buffer
 677         0,                                                // No auxiliary buffer
 678         PFD_MAIN_PLANE,                                   // Main drawing layer
 679         0,                                                // Reserved
 680         0, 0, 0                                           // Layer makes ignored
 681     };
 682 
 683     if (!(hDC = GetDC(hWnd))) {                           // Did we get a device context
 684         KillGLWindow();                                   // Reset the display
 685         MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 686         return FALSE;                                     // Return FALSE
 687     }
 688 
 689     if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {  // Did window find a matching pixel format
 690         KillGLWindow();                                   // Reset the display
 691         MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 692         return FALSE;                                     // Return FALSE;
 693     }
 694 
 695     if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {        // Are we able to set the pixel format
 696         KillGLWindow();                                   // Reset the display
 697         MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 698         return FALSE;                                     // Return FALSE;
 699     }
 700 
 701     if (!(hRC = wglCreateContext(hDC))) {                 // Are we able to rendering context
 702         KillGLWindow();                                   // Reset the display
 703         MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 704         return FALSE;                                     // Return FASLE;
 705     }
 706 
 707     if (!wglMakeCurrent(hDC, hRC)) {                      // Try to activate the rendering context
 708         KillGLWindow();                                   // Reset the display
 709         MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 710         return FALSE;                                     // Return FALSE    
 711     }
 712 
 713     /*
 714      *  ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen.
 715      */
 716     ShowWindow(hWnd, SW_SHOW);                            // Show the window
 717     SetForegroundWindow(hWnd);                            // slightly higher priority
 718     SetFocus(hWnd);                                       // Sets keyboard focus to the window
 719     ReSizeGLScene(width, height);                         // Set up our perspective GL screen
 720 
 721 /*
 722  *  we can set up lighting, textures, and anything else that needs to be setup in InitGL().
 723  */
 724 if (!InitGL()) {                                      // Initialize our newly created GL window
 725     KillGLWindow();                                   // Reset the display
 726     MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 727     return FALSE;                                     // Return FALSE
 728 }
 729 return TRUE;
 730 }
 731 
 732 LRESULT CALLBACK WndProc(HWND hWnd,                       // Handle for this window
 733     UINT uMsg,                                            // Message for this window
 734     WPARAM wParam,                                        // Additional message information
 735     LPARAM lParam)                                        // Additional message information
 736 {
 737     switch (uMsg) {                                       // Check for window message
 738     case WM_ACTIVATE: {                               // Check minimization state
 739         if (!HIWORD(wParam)) {
 740             active = TRUE;                            // Program is active
 741         }
 742         else {
 743             active = FALSE;                           // Program is no longer active
 744         }
 745         return 0;                                     // Return to the message loop
 746     }
 747     case WM_SYSCOMMAND: {                             // Intercept system commands
 748         switch (wParam) {                             // Check system calls
 749         case SC_SCREENSAVE:                       // Screensaver trying to start
 750         case SC_MONITORPOWER:                     // Monitor trying to enter powersave
 751             return 0;                                 // Prevent form happening
 752         }
 753         break;                                        // Exit
 754     }
 755     case WM_CLOSE: {                                  // Did we receive a close message
 756         PostQuitMessage(0);                           // Send a quit message
 757         return 0;
 758     }
 759     case WM_KEYDOWN: {                                // Is a key being held down
 760         keys[wParam] = TRUE;                          // if so, mark it as TRUE
 761         return 0;                                     // Jump back
 762     }
 763     case WM_KEYUP: {                                  // Has a key been released
 764         keys[wParam] = FALSE;                         // if so, mark it as FALSE
 765         return 0;                                     // Jump back
 766     }
 767     case WM_SIZE: {                                   // Resize the OpenGL window
 768         ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));   // LoWord = width HiWord = height
 769         return 0;                                     // Jump back
 770     }
 771     }
 772     return DefWindowProc(hWnd, uMsg, wParam, lParam);     // Pass all unhandled message to DefWindwProc
 773 }
 774 
 775 int WINAPI WinMain(HINSTANCE hInstance,                   // Instance
 776     HINSTANCE hPrevInstance,                              // Previous instance
 777     LPSTR lpCmdLine,                                      // Command line parameters
 778     int nCmdShow)                                         // Window show state
 779 {
 780     MSG msg;                                              // Window message structure
 781     BOOL done = FALSE;                                    // Bool variable to exit loop
 782                                                           // Ask the user which screen mode they prefer
 783     if (MessageBox(NULL, "Would you like to run in fullscreen mode?",
 784         "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO)
 785     {
 786         fullscreen = FALSE;                               // Window mode
 787     }
 788     // Create our OpenGL window
 789     if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {  // (Modified)
 790         return 0;                                         // Quit if window was not create
 791     }
 792     /******************************************************************************************************************************************/
 793     /******************************************************************************************************************************************/
 794     ResetObjects();                                       // Set player / enemy starting position
 795     TimerInit();                                          // Initialize the timer
 796 
 797     while (!done) {                                       // Loop that runs until donw = TRUE
 798         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {   // Is there a message wating
 799             if (msg.message == WM_QUIT) {                 // Havw we received a quit message
 800                 done = TRUE;                              // if so done  = TRUE
 801             }
 802             else {                                        // If not, deal with window message
 803                 TranslateMessage(&msg);                   // Translate message
 804                 DispatchMessage(&msg);                    // Dispatch message
 805             }
 806         }
 807         else {
 808 
 809             float start = TimerGetTime();                 // Grab timer value before we draw
 810 
 811             // Draw the scene. Watch for ESC key and quit message from DrawGLScene()
 812             if (active) {                                 // Program active
 813                 if (keys[VK_ESCAPE]) {                    // Was ESC pressed
 814                     done = TRUE;                          // ESC signalled a quit
 815                 }
 816                 else {                                    // Not time to quit, update screen
 817                     DrawGLScene();                        // Draw scene
 818                     SwapBuffers(hDC);                     // Swap buffers (double buffering)
 819                 }
 820             }
 821             // Waste Cycles On Fast Systems
 822             while (TimerGetTime() < start + float(steps[adjust] * 2.0f)) {}
 823 
 824             if (keys['A'] && !ap) {
 825                 ap = TRUE;
 826                 anti = !anti;
 827             }
 828             if (!keys['A']) {
 829                 ap = FALSE;
 830             }
 831             if (!gameover && active) {                    // If game isn't over and active move objects
 832                 for (loop1 = 0; loop1 < (stage * level); ++loop1) {
 833                     if ((enemy[loop1].x < player.x) && (enemy[loop1].fy == enemy[loop1].y * 40)) {
 834                         enemy[loop1].x++;                 // Move the enemy right
 835                     }
 836                     if ((enemy[loop1].x > player.x) && (enemy[loop1].fy == enemy[loop1].y * 40)) {
 837                         enemy[loop1].x--;                 // Move the enemy left
 838                     }
 839                     if ((enemy[loop1].y < player.y) && (enemy[loop1].fx == enemy[loop1].x * 60)) {
 840                         enemy[loop1].y++;                 // Move the enemy down
 841                     }
 842                     if ((enemy[loop1].y > player.y) && (enemy[loop1].fx == enemy[loop1].x * 60)) {
 843                         enemy[loop1].y--;                 // Move the enemy up
 844                     }
 845 
 846                     if (delay > (3 - level) && (hourglass.fx != 2)) {
 847                         delay = 0;
 848                         for (loop2 = 0; loop2 < (stage * level); ++loop2) {
 849                             if (enemy[loop2].fx < enemy[loop2].x * 60) {
 850                                 enemy[loop2].fx += steps[adjust];
 851                                 enemy[loop2].spin += steps[adjust];
 852                             }
 853                             if (enemy[loop2].fx > enemy[loop2].x * 60) {
 854                                 enemy[loop2].fx -= steps[adjust];
 855                                 enemy[loop2].spin -= steps[adjust];
 856                             }
 857                             if (enemy[loop2].fy < enemy[loop2].y * 40) {
 858                                 enemy[loop2].fy += steps[adjust];
 859                                 enemy[loop2].spin += steps[adjust];
 860                             }
 861                             if (enemy[loop2].fy > enemy[loop2].y * 40) {
 862                                 enemy[loop2].fy -= steps[adjust];
 863                                 enemy[loop2].spin -= steps[adjust];
 864                             }
 865                         }
 866                     }
 867 
 868                     if ((enemy[loop1].fx == player.fx) && (enemy[loop1].fy == player.fy)) {
 869                         lives--;
 870                         if (lives == 0) {
 871                             gameover = TRUE;
 872                         }
 873                         ResetObjects();
 874                         PlaySound("Die.wav", NULL, SND_SYNC);
 875                     }
 876                 }
 877 
 878                 if (keys[VK_RIGHT] && (player.x < 10) && (player.fx == player.x * 60) &&
 879                     (player.fy == player.y * 40))
 880                 {
 881                     // Make current horizontal border as filled
 882                     hline[player.x][player.y] = TRUE;
 883                     player.x++;                                 // Move the player right
 884                 }
 885                 if (keys[VK_LEFT] && (player.x > 0) && (player.fx == player.x * 60) &&
 886                     (player.fy == player.y * 40))
 887                 {
 888                     player.x--;
 889                     hline[player.x][player.y] = TRUE;
 890                 }
 891                 if (keys[VK_DOWN] && (player.y < 10) && (player.fx == player.x * 60) &&
 892                     (player.fy == player.y * 40))
 893                 {
 894                     vline[player.x][player.y] = TRUE;
 895                     player.y++;
 896                 }
 897                 if (keys[VK_UP] && (player.y > 0) && (player.fx == player.x * 60) &&
 898                     (player.fy == player.y * 40))
 899                 {
 900                     player.y--;
 901                     vline[player.x][player.y] = TRUE;
 902                 }
 903 
 904                 if (player.fx < player.x * 60) {
 905                     player.fx += steps[adjust];
 906                 }
 907                 if (player.fx > player.x * 60) {
 908                     player.fx -= steps[adjust];
 909                 }
 910                 if (player.fy < player.y * 40) {
 911                     player.fy += steps[adjust];
 912                 }
 913                 if (player.fy > player.y * 40) {
 914                     player.fy -= steps[adjust];
 915                 }
 916             }
 917             else {
 918                 if (keys[' ']) {
 919                     gameover = FALSE;
 920                     filled = TRUE;
 921                     level = 1;
 922                     level2 = 1;
 923                     stage = 0;
 924                     lives = 5;
 925                 }
 926             }
 927 
 928             if (filled) {
 929                 PlaySound("Complete.wav", NULL, SND_SYNC);
 930                 stage++;
 931                 if (stage > 3) {
 932                     stage = 1;
 933                     level++;
 934                     level2++;
 935                     if (level > 3) {
 936                         level = 3;
 937                         lives++;
 938                         if (lives > 5) {
 939                             lives = 5;
 940                         }
 941                     }
 942                 }
 943                 ResetObjects();
 944                 for (loop1 = 0; loop1 < 11; ++loop1) {
 945                     for (loop2 = 0; loop2 < 11; ++loop2) {
 946                         if (loop1 < 10) {
 947                             hline[loop1][loop2] = FALSE;
 948                         }
 949                         if (loop2 < 10) {
 950                             vline[loop1][loop2] = FALSE;
 951                         }
 952                     }
 953                 }
 954             }
 955 
 956             if ((player.fx == hourglass.x * 60) && (player.fy == hourglass.y * 40) &&
 957                 (hourglass.fx == 1))
 958             {
 959                 PlaySound("freeze.wav", NULL, SND_ASYNC | SND_LOOP);
 960                 hourglass.fx = 2;
 961                 hourglass.fy = 0;
 962             }
 963 
 964             player.spin += 0.5f * steps[adjust];
 965             if (player.spin > 360.0f) {
 966                 player.spin -= 360.0f;
 967             }
 968             hourglass.spin -= 0.25f * steps[adjust];
 969             if (hourglass.spin < 0.0f) {
 970                 hourglass.spin += 360.0f;
 971             }
 972             hourglass.fy += steps[adjust];
 973             if ((hourglass.fx == 0) && (hourglass.fy > 6000 / level)) {
 974                 PlaySound("hourglass.wav", NULL, SND_ASYNC);
 975                 hourglass.x = rand() % 10 + 1;
 976                 hourglass.y = rand() % 11;
 977                 hourglass.fx = 1;
 978                 hourglass.fy = 0;
 979             }
 980             if ((hourglass.fx == 1) && (hourglass.fy > 6000 / level)) {
 981                 hourglass.fx = 0;
 982                 hourglass.fy = 0;
 983             }
 984             if ((hourglass.fx == 2) && (hourglass.fy > 500 + (500 * level))) {
 985                 PlaySound(NULL, NULL, 0);
 986                 hourglass.fx = 0;
 987                 hourglass.fy = 0;
 988             }
 989             delay++;
 990             /*
 991             *  It allows us to press the F1 key to switch from fullscreen mode to
 992             *  windowed mode or windowed mode to fullscreen mode.
 993             */
 994             if (keys[VK_F1]) {                            // Is F1 being pressed
 995                 keys[VK_F1] = FALSE;                      // If so make key FASLE
 996                 KillGLWindow();                           // Kill our current window
 997                 fullscreen = !fullscreen;                 // Toggle fullscreen / window mode
 998                 //Recreate our OpenGL window(modified)
 999                 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {
1000                     return 0;                             // Quit if window was not create
1001                 }
1002             }
1003         }
1004     }
1005     // Shutdown
1006     KillGLWindow();                                       // Kill the window
1007     return (msg.wParam);                                  // Exit the program
1008 }
1009 /******************************************************************************************************************************************/
1010 /******************************************************************************************************************************************/

Thanks for Nehe's tutorials, this is his home.

posted @ 2016-07-20 22:54  clairvoyant  阅读(398)  评论(0编辑  收藏  举报