outdated: 13.Bitmap Fonts
如何在屏幕上显示字体,同时颜色变换且是动态移动的?
CreateFont()是建立字体主要的函数,在MSDN中有详细的解释。同时的glGenLists()函数创建空的显示列表,主要是为了表示26个字母。SelectObject()函数以及DeleteObject()函数是对具体字体对象的操作。
wglUseFontBitmaps()函数批量的产生显示字符用的显示列表在当前句柄中。
在原作者编写的glPrint()函数中,使用到了va_start()、va_end()函数,那是为了访问变量参数列表。vsprintf()函数和sprintf()函数前两个参数一样,后一个参数为指向参数列表的指针。
glPushAttrib()、glPopAttrib()函数操作于显示列表。glListBase()函数设置显示列表作用于glCallLists()函数。
glRasterPos2f()函数指定像素操作光栅化位置。
代码如下,同样修改位于双行星号内。
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 GLuint base; 32 GLfloat cnt1; 33 GLfloat cnt2; 34 35 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc 36 37 GLvoid BuildFont(GLvoid) 38 { 39 HFONT font; // Windows font ID 40 HFONT oldfont; // Used for good house keeping 41 42 base = glGenLists(96); // Storage for 95 characters 43 44 // The CreateFont function creates a logical font with the specified characteristics. 45 // The logical font can subsequently be selected as the font for any device. 46 font = CreateFont(-24, // Height of font 47 0, // Width of font 48 0, // Angle of escapement 49 0, // Orientation angle 50 FW_BOLD, // Font weight 51 FALSE, // Italic 52 FALSE, // Underline 53 FALSE, // Strikeout 54 ANSI_CHARSET, // Character set identifier 55 OUT_TT_PRECIS, // Output precision 56 CLIP_DEFAULT_PRECIS, // Clipping precision 57 ANTIALIASED_QUALITY, // Output quality 58 FF_DONTCARE | DEFAULT_PITCH, // Family and pitch 59 "Courier New"); // Font name 60 61 // The SelectObject function selects an object into the specified device context (DC). 62 // The new object replaces the previous object of the same type. 63 oldfont = (HFONT)SelectObject(hDC, font); 64 // The wglUseFontBitmaps function creates a set of bitmap display lists 65 // for use in the current OpenGL rendering context. The set of bitmap display lists 66 // is based on the glyphs in the currently selected font in the device context. 67 // You can then use bitmaps to draw characters in an OpenGL image. 68 69 // The wglUseFontBitmaps function creates count display lists, one for each of 70 // a run of count glyphs that begins with the first glyph in the hdc parameter's selected fonts. 71 wglUseFontBitmaps(hDC, 32, 96, base); // Builds 96 characters starting at character 32 72 SelectObject(hDC, oldfont); 73 // The DeleteObject function deletes a logical pen, brush, font, bitmap, region, 74 // or palette, freeing all system resources associated with the object. 75 // After the object is deleted, the specified handle is no longer valid. 76 DeleteObject(font); 77 } 78 79 GLvoid KillFont(GLvoid) 80 { 81 glDeleteLists(base, 96); // Delete all 96 characters 82 } 83 84 GLvoid glPrint(const char* fmt, ...) 85 { 86 char text[256]; // Holds ours string 87 va_list ap; // Pointer to list of arguments 88 89 if (fmt == NULL) { 90 return; 91 } 92 va_start(ap, fmt); // Parses the string for variables 93 vsprintf(text, fmt, ap); // And converts symbols to actual numbers 94 va_end(ap); // Results are stored in text 95 glPushAttrib(GL_LIST_BIT); // Pushes the display list bits 96 glListBase(base - 32); // Sets th base charcter to 32 97 98 glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);// Draws the display list text 99 glPopAttrib(); // Pops the display list bits 100 } 101 /******************************************************************************************************************************************/ 102 /******************************************************************************************************************************************/ 103 104 GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize and initialize the GL window 105 { 106 if (height == 0) { // Prevent a divide by zero by 107 height = 1; // Making height equal one 108 } 109 110 glViewport(0, 0, width, height); // Reset the current viewport 111 112 /* 113 * The following lines set the screen up for a perspective view. 114 * Meaning things in the distance get smaller. This creates a realistic looking scene. 115 * The perspective is calculated with a 45 degree viewing angle based on 116 * the windows width and height. The 0.1f, 100.0f is the starting point and 117 * ending point for how deep we can draw into the screen. 118 * 119 * The projection matrix is responsible for adding perspective to our scene. 120 * glLoadIdentity() restores the selected matrix to it's original state. 121 * The modelview matrix is where our object information is stored. 122 * Lastly we reset the modelview matrix. 123 */ 124 125 glMatrixMode(GL_PROJECTION); // Select the projection matrix 126 glLoadIdentity(); // Reset the projection matrix 127 128 // Calculate the aspect ratio of the window 129 gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); 130 131 glMatrixMode(GL_MODELVIEW); // Seclet the modelview matrix 132 glLoadIdentity(); // Reset the modelview matrix 133 } 134 /******************************************************************************************************************************************/ 135 /******************************************************************************************************************************************/ 136 int InitGL(GLvoid) // All setup for OpenGL goes here 137 { 138 /* 139 * Smooth shading blends colors nicely across a polygon, and smoothes out lighting. 140 */ 141 142 glShadeModel(GL_SMOOTH); // Enables smooth shading 143 glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black background 144 145 glClearDepth(1.0f); // Depth buffer setup 146 147 glDepthFunc(GL_LEQUAL); 148 glEnable(GL_DEPTH_TEST); 149 150 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really nice perspective calculations 151 152 BuildFont(); 153 return TRUE; 154 } 155 /* 156 * For now all we will do is clear the screen to the color we previously decided on, 157 * clear the depth buffer and reset the scene. We wont draw anything yet. 158 */ 159 int DrawGLScene(GLvoid) // Here's where we do all the drawing 160 { 161 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the screen and the depth buffer 162 glLoadIdentity(); 163 glTranslatef(0.0f, 0.0f, -1.0f); 164 165 // Pulsing colors based on text position 166 glColor3f(1.0f * float(cos(cnt1)), 1.0f * float(sin(cnt2)), 1.0f - 0.5f * float(cos(cnt1 + cnt2))); 167 // Position the text on the screen 168 glRasterPos2f(-0.45f + 0.05f * float(cos(cnt1)), 0.35f * float(sin(cnt2))); 169 170 glPrint("Active OpenGL Text - %7.2f", cnt1); 171 172 cnt1 += 0.051f; 173 cnt2 += 0.005f; 174 return TRUE; // everthing went OK 175 } 176 /******************************************************************************************************************************************/ 177 /******************************************************************************************************************************************/ 178 /* 179 * The job of KillGLWindow() is to release the Rendering Context, 180 * the Device Context and finally the Window Handle. 181 */ 182 183 GLvoid KillGLWindow(GLvoid) // Properly kill the window 184 { 185 if (fullscreen) { // Are we in fullscreen mode 186 187 /* 188 * We use ChangeDisplaySettings(NULL,0) to return us to our original desktop. 189 * After we've switched back to the desktop we make the cursor visible again. 190 */ 191 192 ChangeDisplaySettings(NULL, 0); // if so switch back to the desktop 193 ShowCursor(TRUE); // Show mouse pointer 194 } 195 196 if (hRC) { // Do we have a rendering context 197 if (!wglMakeCurrent(NULL, NULL)) { // Are we able to release the DC and RC contexts 198 MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 199 } 200 201 if (!wglDeleteContext(hRC)) { // Are we able to delete the RC 202 MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 203 hRC = NULL; // Set RC to NULL 204 } 205 206 if (hDC && !ReleaseDC(hWnd, hDC)) { // Are we able to release the DC 207 MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 208 hDC = NULL; // Set DC to NULL 209 } 210 if (hWnd && !DestroyWindow(hWnd)) { // Are we able to destroy the window 211 MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 212 hWnd = NULL; // Set hWnd to NULL 213 } 214 215 if (!UnregisterClass("OpenGL", hInstance)) { // Are we able to unregister class 216 MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 217 hInstance = NULL; // Set hInstance to NULL 218 } 219 } 220 } 221 222 /* 223 * The next section of code creates our OpenGL Window. 224 */ 225 226 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) 227 { 228 /* 229 * Find a pixel format that matches the one we want 230 */ 231 GLuint PixelFormat; // Holds the result after serching for a match 232 233 /* 234 * Before you create a window, you MUST register a Class for the window 235 */ 236 WNDCLASS wc; // Windows class structure 237 238 /* 239 * dwExStyle and dwStyle will store the Extended and normal Window Style Information. 240 */ 241 DWORD dwExStyle; // Window extend style 242 DWORD dwStyle; // Window style 243 244 RECT WindowRect; // Grabs rectangle upper left/lower right values 245 WindowRect.left = (long)0; // Set left value to 0 246 WindowRect.right = (long)width; // Set right value to requested width 247 WindowRect.top = (long)0; // Set top value to 0 248 WindowRect.bottom = (long)height; // Set bottom value to requested height 249 250 fullscreen = fullscreenflag; // Set the global fullscreen flag 251 252 /* 253 * The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized. 254 * CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications. 255 * WndProc is the procedure that watches for messages in our program. 256 * No extra Window data is used so we zero the two fields. Then we set the instance. 257 * Next we set hIcon to NULL meaning we don't want an ICON in the Window, 258 * and for a mouse pointer we use the standard arrow. The background color doesn't matter 259 * (we set that in GL). We don't want a menu in this Window so we set it to NULL, 260 * and the class name can be any name you want. I'll use "OpenGL" for simplicity. 261 */ 262 hInstance = GetModuleHandle(NULL); // Grab an instance for our window 263 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw on move, and own DC for window 264 wc.lpfnWndProc = (WNDPROC)WndProc; // WndProc handles message 265 wc.cbClsExtra = 0; // No extra window date 266 wc.cbWndExtra = 0; // No extra window date 267 wc.hInstance = hInstance; // set the instance 268 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load the default icon 269 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the arrow pointer 270 wc.hbrBackground = NULL; // No background requried for GL 271 wc.lpszMenuName = NULL; // We don't want a menu 272 wc.lpszClassName = "OpenGL"; // set the class name 273 274 if (!RegisterClass(&wc)) { // Attempt to register the window class 275 MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 276 return FALSE; // Exit and return false 277 } 278 279 if (fullscreen) { // attempt fullsreen model 280 281 /* 282 T* here are a few very important things you should keep in mind when switching to full screen mode. 283 * Make sure the width and height that you use in fullscreen mode is the same as 284 * the width and height you plan to use for your window, and most importantly, 285 * set fullscreen mode BEFORE you create your window. 286 */ 287 DEVMODE dmScreenSettings; // Device mode 288 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared 289 dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size of devmode structure 290 dmScreenSettings.dmPelsWidth = width; // Select window width 291 dmScreenSettings.dmPelsHeight = height; // Select window height 292 dmScreenSettings.dmBitsPerPel = bits; // Select bits per pixel 293 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 294 295 /* 296 * In the line below ChangeDisplaySettings tries to switch to a mode that matches 297 * what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes, 298 * because it's supposed to remove the start bar at the bottom of the screen, 299 * plus it doesn't move or resize the windows on your desktop when you switch to 300 * fullscreen mode and back. 301 */ 302 //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar 303 if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { 304 //If the mode fails, offer two options. Quit or run in a window 305 if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use" 306 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) 307 { 308 fullscreen = FALSE; // Select windowed mode (fullscreen=FLASE) 309 } 310 else { 311 // Pop up a message box letting user know the programe is closing. 312 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP); 313 return FALSE; // Exit and return FALSE 314 } 315 } 316 } 317 318 if (fullscreen) { // Are we still in fullscreen mode 319 320 /* 321 * If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW, 322 * which force a top level window down to the taskbar once our window is visible. 323 * For the window style we'll create a WS_POPUP window. 324 * This type of window has no border around it, making it perfect for fullscreen mode. 325 326 * Finally, we disable the mouse pointer. If your program is not interactive, 327 * it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though. 328 */ 329 dwExStyle = WS_EX_APPWINDOW; // Window extended style 330 dwStyle = WS_POPUP; // Window style 331 ShowCursor(FALSE); // Hide mosue pointer 332 } 333 else { 334 335 /* 336 * If we're using a window instead of fullscreen mode, 337 * we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. 338 * For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. 339 * WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, 340 * window menu, and minimize / maximize buttons. 341 */ 342 dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window extended style 343 dwStyle = WS_OVERLAPPEDWINDOW; // Window style 344 } 345 346 /* 347 * By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders, 348 * instead, the window will be made larger to account for the pixels needed to draw the window border. 349 * In fullscreen mode, this command has no effect. 350 */ 351 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust window to true resqusted 352 353 /* 354 * WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. 355 * These styles prevent other windows from drawing over or into our OpenGL Window. 356 */ 357 if (!(hWnd = CreateWindowEx(dwExStyle, // Extended style for the window 358 "OpenGL", // Class name 359 title, // Window title 360 WS_CLIPSIBLINGS | // Requried window style 361 WS_CLIPCHILDREN | // Requried window style 362 dwStyle, // Select window style 363 0, 0, // Window position 364 WindowRect.right - WindowRect.left, // Calculate adjusted window width 365 WindowRect.bottom - WindowRect.top, // Calculate adjusted window height 366 NULL, // No parent window 367 NULL, // No menu 368 hInstance, // Instance 369 NULL))) // Don't pass anything to WM_CREATE 370 { 371 KillGLWindow(); //Reset the display 372 MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 373 return FALSE; // Retrurn FALSE; 374 } 375 376 /* 377 * aside from the stencil buffer and the (slow) accumulation buffer 378 */ 379 static PIXELFORMATDESCRIPTOR pfd = // pfd tells windows how we want things to be 380 { 381 sizeof(PIXELFORMATDESCRIPTOR), // Size of this pixel format descriptor 382 1, // Version number 383 PFD_DRAW_TO_WINDOW | // Format must support window 384 PFD_SUPPORT_OPENGL | // Format must support OpenGL 385 PFD_DOUBLEBUFFER, // Must support double buffer 386 PFD_TYPE_RGBA, // Request an RGBA format 387 bits, // Select our color depth 388 0, 0, 0, 0, 0, 0, // Color bits ignored 389 0, // No alpha buffer 390 0, // shift bit ignored 391 0, // No accumulation buffer 392 0, 0, 0, 0, // Accumulation bits ignored 393 16, // 16Bits Z_Buffer (depth buffer) 394 0, // No stencil buffer 395 0, // No auxiliary buffer 396 PFD_MAIN_PLANE, // Main drawing layer 397 0, // Reserved 398 0, 0, 0 // Layer makes ignored 399 }; 400 401 if (!(hDC = GetDC(hWnd))) { // Did we get a device context 402 KillGLWindow(); // Reset the display 403 MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 404 return FALSE; // Return FALSE 405 } 406 407 if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) { // Did window find a matching pixel format 408 KillGLWindow(); // Reset the display 409 MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 410 return FALSE; // Return FALSE; 411 } 412 413 if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { // Are we able to set the pixel format 414 KillGLWindow(); // Reset the display 415 MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 416 return FALSE; // Return FALSE; 417 } 418 419 if (!(hRC = wglCreateContext(hDC))) { // Are we able to rendering context 420 KillGLWindow(); // Reset the display 421 MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 422 return FALSE; // Return FASLE; 423 } 424 425 if (!wglMakeCurrent(hDC, hRC)) { // Try to activate the rendering context 426 KillGLWindow(); // Reset the display 427 MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 428 return FALSE; // Return FALSE 429 } 430 431 /* 432 * ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen. 433 */ 434 ShowWindow(hWnd, SW_SHOW); // Show the window 435 SetForegroundWindow(hWnd); // slightly higher priority 436 SetFocus(hWnd); // Sets keyboard focus to the window 437 ReSizeGLScene(width, height); // Set up our perspective GL screen 438 439 /* 440 * we can set up lighting, textures, and anything else that needs to be setup in InitGL(). 441 */ 442 if (!InitGL()) { // Initialize our newly created GL window 443 KillGLWindow(); // Reset the display 444 MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 445 return FALSE; // Return FALSE 446 } 447 return TRUE; 448 } 449 450 LRESULT CALLBACK WndProc(HWND hWnd, // Handle for this window 451 UINT uMsg, // Message for this window 452 WPARAM wParam, // Additional message information 453 LPARAM lParam) // Additional message information 454 { 455 switch (uMsg) { // Check for window message 456 case WM_ACTIVATE: { // Check minimization state 457 if (!HIWORD(wParam)) { 458 active = TRUE; // Program is active 459 } 460 else { 461 active = FALSE; // Program is no longer active 462 } 463 return 0; // Return to the message loop 464 } 465 case WM_SYSCOMMAND: { // Intercept system commands 466 switch (wParam) { // Check system calls 467 case SC_SCREENSAVE: // Screensaver trying to start 468 case SC_MONITORPOWER: // Monitor trying to enter powersave 469 return 0; // Prevent form happening 470 } 471 break; // Exit 472 } 473 case WM_CLOSE: { // Did we receive a close message 474 PostQuitMessage(0); // Send a quit message 475 return 0; 476 } 477 case WM_KEYDOWN: { // Is a key being held down 478 keys[wParam] = TRUE; // if so, mark it as TRUE 479 return 0; // Jump back 480 } 481 case WM_KEYUP: { // Has a key been released 482 keys[wParam] = FALSE; // if so, mark it as FALSE 483 return 0; // Jump back 484 } 485 case WM_SIZE: { // Resize the OpenGL window 486 ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord = width HiWord = height 487 return 0; // Jump back 488 } 489 } 490 return DefWindowProc(hWnd, uMsg, wParam, lParam); // Pass all unhandled message to DefWindwProc 491 } 492 493 int WINAPI WinMain(HINSTANCE hInstance, // Instance 494 HINSTANCE hPrevInstance, // Previous instance 495 LPSTR lpCmdLine, // Command line parameters 496 int nCmdShow) // Window show state 497 { 498 MSG msg; // Window message structure 499 BOOL done = FALSE; // Bool variable to exit loop 500 // Ask the user which screen mode they prefer 501 if (MessageBox(NULL, "Would you like to run in fullscreen mode?", 502 "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO) 503 { 504 fullscreen = FALSE; // Window mode 505 } 506 // Create our OpenGL window 507 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) { // (Modified) 508 return 0; // Quit if window was not create 509 } 510 511 while (!done) { // Loop that runs until donw = TRUE 512 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // Is there a message wating 513 if (msg.message == WM_QUIT) { // Havw we received a quit message 514 done = TRUE; // if so done = TRUE 515 } 516 else { // If not, deal with window message 517 TranslateMessage(&msg); // Translate message 518 DispatchMessage(&msg); // Dispatch message 519 } 520 } 521 else { 522 // Draw the scene. Watch for ESC key and quit message from DrawGLScene() 523 if (active) { // Program active 524 if (keys[VK_ESCAPE]) { // Was ESC pressed 525 done = TRUE; // ESC signalled a quit 526 } 527 else { // Not time to quit, update screen 528 DrawGLScene(); // Draw scene 529 SwapBuffers(hDC); // Swap buffers (double buffering) 530 } 531 } 532 533 /* 534 * It allows us to press the F1 key to switch from fullscreen mode to 535 * windowed mode or windowed mode to fullscreen mode. 536 */ 537 /******************************************************************************************************************************************/ 538 /******************************************************************************************************************************************/ 539 /******************************************************************************************************************************************/ 540 /******************************************************************************************************************************************/ 541 if (keys[VK_F1]) { // Is F1 being pressed 542 keys[VK_F1] = FALSE; // If so make key FASLE 543 KillGLWindow(); // Kill our current window 544 fullscreen = !fullscreen; // Toggle fullscreen / window mode 545 //Recreate our OpenGL window(modified) 546 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) { 547 return 0; // Quit if window was not create 548 } 549 } 550 } 551 } 552 // Shutdown 553 KillGLWindow(); // Kill the window 554 return (msg.wParam); // Exit the program 555 }
Thanks for Nehe's tutorials, this is his home.