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