这是一个简单的小游戏,类型相当于amidar,不过也有1000行,手困眼花......UPDOWNLEFTRIGHT控制,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 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.