outdated: 19.Particle Engine Using Triangle Strips
粒子散射做出来是比较酷炫的,每个粒子为一个结构体。
1 typedef struct { 2 bool active; // Active 3 float life; // Particle life 4 float fade; // Fade speed 5 float r, g, b; 6 float x, y, z; // Position 7 float xi, yi, zi; // Direction 8 float xg, yg, zg; // Gravity 9 } particles;
活动状态、生命周期、消褪时间、颜色、位置坐标、方向坐标、重力方向都有,可以任意调节。
当时在绘制函数中发现原文用的是三角形,为什么不用四边形?
1 glBegin(GL_TRIANGLE_STRIP)
因为用Quads很慢,现在的GPU都呈现三角形,尽力呈现(其实为相似)四边形。原因此处。
在InitGL()函数内,对1000个结构体进行初始化,除了位置坐标和颜色。
在DrawGLScene()函数内,再对位置坐标和颜色修改后进行绘制。
我修改了部分按键,最终为W/S/A/D为重力方向,UP/DOWN/LEFT/RIGHT为总体方向,小键盘的-/+为粒子速度的调节,PgUp/PgDn为粒子于屏幕的远近,tab键让所有粒子都回到原点,空格键切换颜色,enter键位单色和多色之间的转换。
原图:
当绘制的为点时:
当绘制的为线时:
代码如下,同样修改部分位于双行星号内。
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 #define MAX_PARTICLES 1000 32 bool rainbow = true; 33 bool rp; 34 bool sp; // Spacebar pressed 35 36 float slowdown = 2.0f; // Slow down particles 37 float xspeed; 38 float yspeed; 39 float zoom = -40.0f; // Used to zoom out 40 41 GLuint loop; 42 GLuint col; 43 GLuint delay; 44 GLuint texture[1]; 45 46 typedef struct { 47 bool active; // Active 48 float life; // Particle life 49 float fade; // Fade speed 50 float r, g, b; 51 float x, y, z; // Position 52 float xi, yi, zi; // Direction 53 float xg, yg, zg; // Gravity 54 } particles; 55 56 particles particle[MAX_PARTICLES]; 57 58 static GLfloat colors[12][3] = { 59 { 1.0f,0.5f,0.5f },{ 1.0f,0.75f,0.5f },{ 1.0f,1.0f,0.5f },{ 0.75f,1.0f,0.5f }, 60 { 0.5f,1.0f,0.5f },{ 0.5f,1.0f,0.75f },{ 0.5f,1.0f,1.0f },{ 0.5f,0.75f,1.0f }, 61 { 0.5f,0.5f,1.0f },{ 0.75f,0.5f,1.0f },{ 1.0f,0.5f,1.0f },{ 1.0f,0.5f,0.75f } 62 }; 63 64 /******************************************************************************************************************************************/ 65 /******************************************************************************************************************************************/ 66 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc 67 68 AUX_RGBImageRec* LoadBMP(char* Filename) 69 { 70 FILE* File = NULL; 71 72 if (!Filename) { 73 return NULL; 74 } 75 76 File = fopen(Filename, "r"); 77 if (File) { 78 fclose(File); 79 return auxDIBImageLoad(Filename); 80 } 81 82 return NULL; 83 } 84 85 int LoadGLTextures() 86 { 87 int Status = FALSE; 88 89 /******************************************************************************************************************************************/ 90 /******************************************************************************************************************************************/ 91 AUX_RGBImageRec* TextureImage[1]; 92 93 memset(TextureImage, 0, sizeof(void*) * 1); 94 95 if (TextureImage[0] = LoadBMP("1.bmp")) { 96 Status = TRUE; 97 glGenTextures(3, &texture[0]); 98 99 glBindTexture(GL_TEXTURE_2D, texture[0]); 100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 102 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 103 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); 104 } 105 106 if (TextureImage[0]) { 107 if (TextureImage[0]->data) { 108 free(TextureImage[0]->data); 109 } 110 free(TextureImage[0]); 111 } 112 return Status; 113 } 114 /******************************************************************************************************************************************/ 115 /******************************************************************************************************************************************/ 116 GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize and initialize the GL window 117 { 118 if (height == 0) { // Prevent a divide by zero by 119 height = 1; // Making height equal one 120 } 121 122 glViewport(0, 0, width, height); // Reset the current viewport 123 124 /* 125 * The following lines set the screen up for a perspective view. 126 * Meaning things in the distance get smaller. This creates a realistic looking scene. 127 * The perspective is calculated with a 45 degree viewing angle based on 128 * the windows width and height. The 0.1f, 100.0f is the starting point and 129 * ending point for how deep we can draw into the screen. 130 * 131 * The projection matrix is responsible for adding perspective to our scene. 132 * glLoadIdentity() restores the selected matrix to it's original state. 133 * The modelview matrix is where our object information is stored. 134 * Lastly we reset the modelview matrix. 135 */ 136 137 glMatrixMode(GL_PROJECTION); // Select the projection matrix 138 glLoadIdentity(); // Reset the projection matrix 139 140 // Calculate the aspect ratio of the window 141 gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); 142 143 glMatrixMode(GL_MODELVIEW); // Seclet the modelview matrix 144 glLoadIdentity(); // Reset the modelview matrix 145 } 146 /******************************************************************************************************************************************/ 147 /******************************************************************************************************************************************/ 148 int InitGL(GLvoid) // All setup for OpenGL goes here 149 { 150 /* 151 * Smooth shading blends colors nicely across a polygon, and smoothes out lighting. 152 */ 153 154 if (!LoadGLTextures()) { 155 return FALSE; 156 } 157 158 glEnable(GL_TEXTURE_2D); 159 glShadeModel(GL_SMOOTH); // Enables smooth shading 160 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black background 161 162 glClearDepth(1.0f); // Depth buffer setup 163 164 glDisable(GL_DEPTH_TEST); 165 glEnable(GL_BLEND); 166 glBlendFunc(GL_SRC_ALPHA, GL_ONE); 167 168 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 169 170 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Really nice perspective calculations 171 glBindTexture(GL_TEXTURE_2D, texture[0]); 172 173 for (loop = 0; loop < MAX_PARTICLES; ++loop) { // Initialize all the textures 174 particle[loop].active = true; // Make all the particles active 175 particle[loop].life = 1.0f; // Give all the particles full life 176 particle[loop].fade = float(rand() % 100) / 1000.0f + 0.003f; // Random fade speed 177 178 particle[loop].r = colors[loop * (12 / MAX_PARTICLES)][0]; 179 particle[loop].g = colors[loop * (12 / MAX_PARTICLES)][1]; 180 particle[loop].b = colors[loop * (12 / MAX_PARTICLES)][2]; 181 182 particle[loop].xi = float((rand() % 50) - 26.0f) * 10.0f; // Direction 183 particle[loop].yi = float((rand() % 50) - 25.0f) * 10.0f; 184 particle[loop].zi = float((rand() % 50) - 25.0f) * 10.0f; 185 186 particle[loop].xg = 0.0f; // Gravity 187 particle[loop].yg = -0.8f; 188 particle[loop].zg = 0.0f; 189 } 190 191 return TRUE; 192 } 193 194 /* 195 * For now all we will do is clear the screen to the color we previously decided on, 196 * clear the depth buffer and reset the scene. We wont draw anything yet. 197 */ 198 int DrawGLScene(GLvoid) // Here's where we do all the drawing 199 { 200 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the screen and the depth buffer 201 glLoadIdentity(); 202 203 for (loop = 0; loop < MAX_PARTICLES; ++loop) { 204 if (particle[loop].active) { 205 float x = particle[loop].x; 206 float y = particle[loop].y; 207 float z = particle[loop].z+zoom; 208 209 glColor4f(particle[loop].r, particle[loop].g, particle[loop].b, particle[loop].life); 210 211 glBegin(GL_TRIANGLE_STRIP); 212 glTexCoord2d(1, 1); glVertex3f(x + 0.5f, y + 0.5f, z); // Top right 213 glTexCoord2d(0, 1); glVertex3f(x - 0.5f, y + 0.5f, z); // Top left 214 glTexCoord2d(1, 0); glVertex3f(x + 0.5f, y - 0.5f, z); // Bottom right 215 glTexCoord2d(0, 0); glVertex3f(x - 0.5f, y - 0.5f, z); // Bottom left 216 glEnd(); 217 // Move on the X axis by X speed 218 particle[loop].x += particle[loop].xi / (slowdown * MAX_PARTICLES); 219 // Move on the Y axis by Y speed 220 particle[loop].y += particle[loop].yi / (slowdown * MAX_PARTICLES); 221 // Move On The Z Axis By Z Speed 222 particle[loop].z += particle[loop].zi / (slowdown * MAX_PARTICLES); 223 224 particle[loop].xi += particle[loop].xg; // Take pull on X axis into account 225 particle[loop].yi += particle[loop].yg; // Take pull on Y aixs into account 226 particle[loop].zi += particle[loop].zg; // Take pull on Z axis into account 227 228 particle[loop].life -= particle[loop].fade; // Reduce particles life by 'fade' 229 230 if (particle[loop].life < 0.0f) { 231 particle[loop].life = 1.0; 232 particle[loop].fade = float(rand() % 100) / MAX_PARTICLES + 0.003f; 233 234 particle[loop].x = 0.0f; // Center 235 particle[loop].y = 0.0f; 236 particle[loop].z = 0.0f; 237 238 particle[loop].xi = xspeed + float((rand() % 60) - 32.0f); 239 particle[loop].yi = yspeed + float((rand() % 60) - 32.0f); 240 particle[loop].zi = float((rand() % 60) - 32.0f); 241 242 particle[loop].r = colors[col][0]; 243 particle[loop].g = colors[col][1]; 244 particle[loop].b = colors[col][2]; 245 } 246 247 if (keys['W'] && (particle[loop].yg < 1.5f)) { 248 particle[loop].yg += 0.01f; 249 } 250 if (keys['S'] && (particle[loop].yg > -1.5f)) { 251 particle[loop].yg -= 0.01f; 252 } 253 if (keys['D'] && (particle[loop].xg < 1.5f)) { 254 particle[loop].xg += 0.01f; 255 } 256 if (keys['A'] && (particle[loop].xg > -1.5f)) { 257 particle[loop].xg -= 0.01f; 258 } 259 260 if (keys[VK_TAB]) { 261 particle[loop].x = 0.0f; 262 particle[loop].y = 0.0f; 263 particle[loop].z = 0.0f; 264 particle[loop].xi = float((rand() % 50) - 26.0f) * 10.0f; 265 particle[loop].yi = float((rand() % 50) - 26.0f) * 10.0f; 266 particle[loop].zi = float((rand() % 50) - 26.0f) * 10.0f; 267 } 268 } 269 } 270 271 return TRUE; // everthing went OK 272 } 273 /******************************************************************************************************************************************/ 274 /******************************************************************************************************************************************/ 275 /* 276 * The job of KillGLWindow() is to release the Rendering Context, 277 * the Device Context and finally the Window Handle. 278 */ 279 280 GLvoid KillGLWindow(GLvoid) // Properly kill the window 281 { 282 if (fullscreen) { // Are we in fullscreen mode 283 284 /* 285 * We use ChangeDisplaySettings(NULL,0) to return us to our original desktop. 286 * After we've switched back to the desktop we make the cursor visible again. 287 */ 288 289 ChangeDisplaySettings(NULL, 0); // if so switch back to the desktop 290 ShowCursor(TRUE); // Show mouse pointer 291 } 292 293 if (hRC) { // Do we have a rendering context 294 if (!wglMakeCurrent(NULL, NULL)) { // Are we able to release the DC and RC contexts 295 MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 296 } 297 298 if (!wglDeleteContext(hRC)) { // Are we able to delete the RC 299 MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 300 hRC = NULL; // Set RC to NULL 301 } 302 303 if (hDC && !ReleaseDC(hWnd, hDC)) { // Are we able to release the DC 304 MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 305 hDC = NULL; // Set DC to NULL 306 } 307 if (hWnd && !DestroyWindow(hWnd)) { // Are we able to destroy the window 308 MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 309 hWnd = NULL; // Set hWnd to NULL 310 } 311 312 if (!UnregisterClass("OpenGL", hInstance)) { // Are we able to unregister class 313 MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 314 hInstance = NULL; // Set hInstance to NULL 315 } 316 } 317 /******************************************************************************************************************************************/ 318 /******************************************************************************************************************************************/ 319 /******************************************************************************************************************************************/ 320 /******************************************************************************************************************************************/ 321 } 322 323 /* 324 * The next section of code creates our OpenGL Window. 325 */ 326 327 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) 328 { 329 /* 330 * Find a pixel format that matches the one we want 331 */ 332 GLuint PixelFormat; // Holds the result after serching for a match 333 334 /* 335 * Before you create a window, you MUST register a Class for the window 336 */ 337 WNDCLASS wc; // Windows class structure 338 339 /* 340 * dwExStyle and dwStyle will store the Extended and normal Window Style Information. 341 */ 342 DWORD dwExStyle; // Window extend style 343 DWORD dwStyle; // Window style 344 345 RECT WindowRect; // Grabs rectangle upper left/lower right values 346 WindowRect.left = (long)0; // Set left value to 0 347 WindowRect.right = (long)width; // Set right value to requested width 348 WindowRect.top = (long)0; // Set top value to 0 349 WindowRect.bottom = (long)height; // Set bottom value to requested height 350 351 fullscreen = fullscreenflag; // Set the global fullscreen flag 352 353 /* 354 * The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized. 355 * CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications. 356 * WndProc is the procedure that watches for messages in our program. 357 * No extra Window data is used so we zero the two fields. Then we set the instance. 358 * Next we set hIcon to NULL meaning we don't want an ICON in the Window, 359 * and for a mouse pointer we use the standard arrow. The background color doesn't matter 360 * (we set that in GL). We don't want a menu in this Window so we set it to NULL, 361 * and the class name can be any name you want. I'll use "OpenGL" for simplicity. 362 */ 363 hInstance = GetModuleHandle(NULL); // Grab an instance for our window 364 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw on move, and own DC for window 365 wc.lpfnWndProc = (WNDPROC)WndProc; // WndProc handles message 366 wc.cbClsExtra = 0; // No extra window date 367 wc.cbWndExtra = 0; // No extra window date 368 wc.hInstance = hInstance; // set the instance 369 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load the default icon 370 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the arrow pointer 371 wc.hbrBackground = NULL; // No background requried for GL 372 wc.lpszMenuName = NULL; // We don't want a menu 373 wc.lpszClassName = "OpenGL"; // set the class name 374 375 if (!RegisterClass(&wc)) { // Attempt to register the window class 376 MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 377 return FALSE; // Exit and return false 378 } 379 380 if (fullscreen) { // attempt fullsreen model 381 382 /* 383 T* here are a few very important things you should keep in mind when switching to full screen mode. 384 * Make sure the width and height that you use in fullscreen mode is the same as 385 * the width and height you plan to use for your window, and most importantly, 386 * set fullscreen mode BEFORE you create your window. 387 */ 388 DEVMODE dmScreenSettings; // Device mode 389 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared 390 dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size of devmode structure 391 dmScreenSettings.dmPelsWidth = width; // Select window width 392 dmScreenSettings.dmPelsHeight = height; // Select window height 393 dmScreenSettings.dmBitsPerPel = bits; // Select bits per pixel 394 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 395 396 /* 397 * In the line below ChangeDisplaySettings tries to switch to a mode that matches 398 * what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes, 399 * because it's supposed to remove the start bar at the bottom of the screen, 400 * plus it doesn't move or resize the windows on your desktop when you switch to 401 * fullscreen mode and back. 402 */ 403 //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar 404 if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { 405 //If the mode fails, offer two options. Quit or run in a window 406 if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use" 407 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) 408 { 409 fullscreen = FALSE; // Select windowed mode (fullscreen=FLASE) 410 } 411 else { 412 // Pop up a message box letting user know the programe is closing. 413 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP); 414 return FALSE; // Exit and return FALSE 415 } 416 } 417 } 418 419 if (fullscreen) { // Are we still in fullscreen mode 420 421 /* 422 * If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW, 423 * which force a top level window down to the taskbar once our window is visible. 424 * For the window style we'll create a WS_POPUP window. 425 * This type of window has no border around it, making it perfect for fullscreen mode. 426 427 * Finally, we disable the mouse pointer. If your program is not interactive, 428 * it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though. 429 */ 430 dwExStyle = WS_EX_APPWINDOW; // Window extended style 431 dwStyle = WS_POPUP; // Window style 432 ShowCursor(FALSE); // Hide mosue pointer 433 } 434 else { 435 436 /* 437 * If we're using a window instead of fullscreen mode, 438 * we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. 439 * For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. 440 * WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, 441 * window menu, and minimize / maximize buttons. 442 */ 443 dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window extended style 444 dwStyle = WS_OVERLAPPEDWINDOW; // Window style 445 } 446 447 /* 448 * By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders, 449 * instead, the window will be made larger to account for the pixels needed to draw the window border. 450 * In fullscreen mode, this command has no effect. 451 */ 452 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust window to true resqusted 453 454 /* 455 * WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. 456 * These styles prevent other windows from drawing over or into our OpenGL Window. 457 */ 458 if (!(hWnd = CreateWindowEx(dwExStyle, // Extended style for the window 459 "OpenGL", // Class name 460 title, // Window title 461 WS_CLIPSIBLINGS | // Requried window style 462 WS_CLIPCHILDREN | // Requried window style 463 dwStyle, // Select window style 464 0, 0, // Window position 465 WindowRect.right - WindowRect.left, // Calculate adjusted window width 466 WindowRect.bottom - WindowRect.top, // Calculate adjusted window height 467 NULL, // No parent window 468 NULL, // No menu 469 hInstance, // Instance 470 NULL))) // Don't pass anything to WM_CREATE 471 { 472 KillGLWindow(); //Reset the display 473 MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 474 return FALSE; // Retrurn FALSE; 475 } 476 477 /* 478 * aside from the stencil buffer and the (slow) accumulation buffer 479 */ 480 static PIXELFORMATDESCRIPTOR pfd = // pfd tells windows how we want things to be 481 { 482 sizeof(PIXELFORMATDESCRIPTOR), // Size of this pixel format descriptor 483 1, // Version number 484 PFD_DRAW_TO_WINDOW | // Format must support window 485 PFD_SUPPORT_OPENGL | // Format must support OpenGL 486 PFD_DOUBLEBUFFER, // Must support double buffer 487 PFD_TYPE_RGBA, // Request an RGBA format 488 bits, // Select our color depth 489 0, 0, 0, 0, 0, 0, // Color bits ignored 490 0, // No alpha buffer 491 0, // shift bit ignored 492 0, // No accumulation buffer 493 0, 0, 0, 0, // Accumulation bits ignored 494 16, // 16Bits Z_Buffer (depth buffer) 495 0, // No stencil buffer 496 0, // No auxiliary buffer 497 PFD_MAIN_PLANE, // Main drawing layer 498 0, // Reserved 499 0, 0, 0 // Layer makes ignored 500 }; 501 502 if (!(hDC = GetDC(hWnd))) { // Did we get a device context 503 KillGLWindow(); // Reset the display 504 MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 505 return FALSE; // Return FALSE 506 } 507 508 if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) { // Did window find a matching pixel format 509 KillGLWindow(); // Reset the display 510 MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 511 return FALSE; // Return FALSE; 512 } 513 514 if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { // Are we able to set the pixel format 515 KillGLWindow(); // Reset the display 516 MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 517 return FALSE; // Return FALSE; 518 } 519 520 if (!(hRC = wglCreateContext(hDC))) { // Are we able to rendering context 521 KillGLWindow(); // Reset the display 522 MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 523 return FALSE; // Return FASLE; 524 } 525 526 if (!wglMakeCurrent(hDC, hRC)) { // Try to activate the rendering context 527 KillGLWindow(); // Reset the display 528 MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 529 return FALSE; // Return FALSE 530 } 531 532 /* 533 * ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen. 534 */ 535 ShowWindow(hWnd, SW_SHOW); // Show the window 536 SetForegroundWindow(hWnd); // slightly higher priority 537 SetFocus(hWnd); // Sets keyboard focus to the window 538 ReSizeGLScene(width, height); // Set up our perspective GL screen 539 540 /* 541 * we can set up lighting, textures, and anything else that needs to be setup in InitGL(). 542 */ 543 if (!InitGL()) { // Initialize our newly created GL window 544 KillGLWindow(); // Reset the display 545 MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 546 return FALSE; // Return FALSE 547 } 548 return TRUE; 549 } 550 551 LRESULT CALLBACK WndProc(HWND hWnd, // Handle for this window 552 UINT uMsg, // Message for this window 553 WPARAM wParam, // Additional message information 554 LPARAM lParam) // Additional message information 555 { 556 switch (uMsg) { // Check for window message 557 case WM_ACTIVATE: { // Check minimization state 558 if (!HIWORD(wParam)) { 559 active = TRUE; // Program is active 560 } 561 else { 562 active = FALSE; // Program is no longer active 563 } 564 return 0; // Return to the message loop 565 } 566 case WM_SYSCOMMAND: { // Intercept system commands 567 switch (wParam) { // Check system calls 568 case SC_SCREENSAVE: // Screensaver trying to start 569 case SC_MONITORPOWER: // Monitor trying to enter powersave 570 return 0; // Prevent form happening 571 } 572 break; // Exit 573 } 574 case WM_CLOSE: { // Did we receive a close message 575 PostQuitMessage(0); // Send a quit message 576 return 0; 577 } 578 case WM_KEYDOWN: { // Is a key being held down 579 keys[wParam] = TRUE; // if so, mark it as TRUE 580 return 0; // Jump back 581 } 582 case WM_KEYUP: { // Has a key been released 583 keys[wParam] = FALSE; // if so, mark it as FALSE 584 return 0; // Jump back 585 } 586 case WM_SIZE: { // Resize the OpenGL window 587 ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord = width HiWord = height 588 return 0; // Jump back 589 } 590 } 591 return DefWindowProc(hWnd, uMsg, wParam, lParam); // Pass all unhandled message to DefWindwProc 592 } 593 594 int WINAPI WinMain(HINSTANCE hInstance, // Instance 595 HINSTANCE hPrevInstance, // Previous instance 596 LPSTR lpCmdLine, // Command line parameters 597 int nCmdShow) // Window show state 598 { 599 MSG msg; // Window message structure 600 BOOL done = FALSE; // Bool variable to exit loop 601 // Ask the user which screen mode they prefer 602 if (MessageBox(NULL, "Would you like to run in fullscreen mode?", 603 "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO) 604 { 605 fullscreen = FALSE; // Window mode 606 } 607 // Create our OpenGL window 608 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) { // (Modified) 609 return 0; // Quit if window was not create 610 } 611 612 while (!done) { // Loop that runs until donw = TRUE 613 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // Is there a message wating 614 if (msg.message == WM_QUIT) { // Havw we received a quit message 615 done = TRUE; // if so done = TRUE 616 } 617 else { // If not, deal with window message 618 TranslateMessage(&msg); // Translate message 619 DispatchMessage(&msg); // Dispatch message 620 } 621 } 622 else { 623 // Draw the scene. Watch for ESC key and quit message from DrawGLScene() 624 if (active) { // Program active 625 if (keys[VK_ESCAPE]) { // Was ESC pressed 626 done = TRUE; // ESC signalled a quit 627 } 628 else { // Not time to quit, update screen 629 DrawGLScene(); // Draw scene 630 SwapBuffers(hDC); // Swap buffers (double buffering) 631 } 632 } 633 /******************************************************************************************************************************************/ 634 /******************************************************************************************************************************************/ 635 if (keys[VK_ADD] && (slowdown > 1.0f)) { 636 slowdown -= 0.01f; 637 } 638 if (keys[VK_SUBTRACT] && (slowdown < 4.0f)) { 639 slowdown += 0.01f; 640 } 641 if (keys[VK_PRIOR]) { 642 zoom += 0.01f; 643 } 644 if (keys[VK_NEXT]) { 645 zoom -= 0.01f; 646 } 647 648 if (keys[VK_RETURN]&& !rp) { 649 rp = true; 650 rainbow = !rainbow; 651 } 652 if (!keys[VK_RETURN]) { 653 rp = false; 654 } 655 656 if ((keys[' '] && !sp) || (rainbow && (delay > 25))) { 657 if (keys[' ']) { 658 rainbow = false; 659 } 660 sp = true; 661 delay = 0; 662 col++; 663 if (col > 11) { 664 col = 0; 665 } 666 } 667 if (!keys[' ']) { 668 sp = false; 669 } 670 671 if (keys[VK_UP] && (yspeed < 200)) { 672 yspeed += 1.0f; 673 } 674 if (keys[VK_DOWN] && (yspeed > -200)) { 675 yspeed -= 1.0f; 676 } 677 if (keys[VK_RIGHT] && (xspeed < 200)) { 678 xspeed += 1.0f; 679 } 680 if (keys[VK_LEFT] && (xspeed > -200)) { 681 xspeed -= 1.0f; 682 } 683 delay++; 684 /******************************************************************************************************************************************/ 685 /******************************************************************************************************************************************/ 686 /* 687 * It allows us to press the F1 key to switch from fullscreen mode to 688 * windowed mode or windowed mode to fullscreen mode. 689 */ 690 if (keys[VK_F1]) { // Is F1 being pressed 691 keys[VK_F1] = FALSE; // If so make key FASLE 692 KillGLWindow(); // Kill our current window 693 fullscreen = !fullscreen; // Toggle fullscreen / window mode 694 //Recreate our OpenGL window(modified) 695 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) { 696 return 0; // Quit if window was not create 697 } 698 } 699 } 700 } 701 // Shutdown 702 KillGLWindow(); // Kill the window 703 return (msg.wParam); // Exit the program 704 }
Thanks for Nehe's tutorials, this is his home.