Getting Started With OpenGL Win32

Alright, we have seen an OpenGL in C/C++ using GLUT but it is rarely used. Most of the people prefer Win32 to write an OpenGL application, mostly games.

Win32 is still the best game development platform for PC rather than other languages, such as .NET. But to write games using only Win32 is a lot of overhead, so you can use Simple DirectMedia Layer (SDL) library.

To get started with OpenGL using GLUT, read this article.
See the Wikipedia page of Win32 API also:  https://en.wikipedia.org/wiki/Windows_API
 
To get started with Win32, go through these articles -
First, start Visual Studio and create Win32 Project from a Visual C++ list and give a name to the project. I have created OpenGL_Win32.
Once you create a project, you can see some predefined code in the editor of the file (OpenGL_Win32.cpp).
  1. #include "stdafx.h"  
  2. #include "OpenGL_Win32.h"  
  3.   
  4. #define MAX_LOADSTRING 100  
  5.   
  6. // Global Variables:  
  7. HINSTANCE hInst;                                // current instance  
  8. TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text  
  9. TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name  
  10.   
  11. // Forward declarations of functions included in this code module:  
  12. ATOM                MyRegisterClass(HINSTANCE hInstance);  
  13. BOOL                InitInstance(HINSTANCEint);  
  14. LRESULT CALLBACK    WndProc(HWNDUINTWPARAMLPARAM);  
  15. INT_PTR CALLBACK    About(HWNDUINTWPARAMLPARAM);  
  16.   
  17. int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,  
  18.                      _In_opt_ HINSTANCE hPrevInstance,  
  19.                      _In_ LPTSTR    lpCmdLine,  
  20.                      _In_ int       nCmdShow)  
  21. {  
  22.     UNREFERENCED_PARAMETER(hPrevInstance);  
  23.     UNREFERENCED_PARAMETER(lpCmdLine);  
  24.   
  25.     // TODO: Place code here.  
  26.     MSG msg;  
  27.     HACCEL hAccelTable;  
  28.   
  29.     // Initialize global strings  
  30.     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);  
  31.     LoadString(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);  
  32.     MyRegisterClass(hInstance);  
  33.   
  34.     // Perform application initialization:  
  35.     if (!InitInstance (hInstance, nCmdShow))  
  36.     {  
  37.         return FALSE;  
  38.     }  
  39.   
  40.     hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));  
  41.   
  42.     // Main message loop:  
  43.     while (GetMessage(&msg, NULL, 0, 0))  
  44.     {  
  45.         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  
  46.         {  
  47.             TranslateMessage(&msg);  
  48.             DispatchMessage(&msg);  
  49.         }  
  50.     }  
  51.   
  52.     return (int) msg.wParam;  
  53. }  
  54.   
  55.   
  56.   
  57. //  
  58. //  FUNCTION: MyRegisterClass()  
  59. //  
  60. //  PURPOSE: Registers the window class.  
  61. //  
  62. ATOM MyRegisterClass(HINSTANCE hInstance)  
  63. {  
  64.     WNDCLASSEX wcex;  
  65.   
  66.     wcex.cbSize = sizeof(WNDCLASSEX);  
  67.   
  68.     wcex.style          = CS_HREDRAW | CS_VREDRAW;  
  69.     wcex.lpfnWndProc    = WndProc;  
  70.     wcex.cbClsExtra     = 0;  
  71.     wcex.cbWndExtra     = 0;  
  72.     wcex.hInstance      = hInstance;  
  73.     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT1));  
  74.     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);  
  75.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  
  76.     wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WIN32PROJECT1);  
  77.     wcex.lpszClassName  = szWindowClass;  
  78.     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));  
  79.   
  80.     return RegisterClassEx(&wcex);  
  81. }  
  82.   
  83. //  
  84. //   FUNCTION: InitInstance(HINSTANCE, int)  
  85. //  
  86. //   PURPOSE: Saves instance handle and creates main window  
  87. //  
  88. //   COMMENTS:  
  89. //  
  90. //        In this function, we save the instance handle in a global variable and  
  91. //        create and display the main program window.  
  92. //  
  93. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  
  94. {  
  95.    HWND hWnd;  
  96.   
  97.    hInst = hInstance; // Store instance handle in our global variable  
  98.   
  99.    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,  
  100.       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);  
  101.   
  102.    if (!hWnd)  
  103.    {  
  104.       return FALSE;  
  105.    }  
  106.   
  107.    ShowWindow(hWnd, nCmdShow);  
  108.    UpdateWindow(hWnd);  
  109.   
  110.    return TRUE;  
  111. }  
  112.   
  113. //  
  114. //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)  
  115. //  
  116. //  PURPOSE:  Processes messages for the main window.  
  117. //  
  118. //  WM_COMMAND  - process the application menu  
  119. //  WM_PAINT    - Paint the main window  
  120. //  WM_DESTROY  - post a quit message and return  
  121. //  
  122. //  
  123. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  124. {  
  125.     int wmId, wmEvent;  
  126.     PAINTSTRUCT ps;  
  127.     HDC hdc;  
  128.   
  129.     switch (message)  
  130.     {  
  131.     case WM_COMMAND:  
  132.         wmId    = LOWORD(wParam);  
  133.         wmEvent = HIWORD(wParam);  
  134.         // Parse the menu selections:  
  135.         switch (wmId)  
  136.         {  
  137.         case IDM_ABOUT:  
  138.             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);  
  139.             break;  
  140.         case IDM_EXIT:  
  141.             DestroyWindow(hWnd);  
  142.             break;  
  143.         default:  
  144.             return DefWindowProc(hWnd, message, wParam, lParam);  
  145.         }  
  146.         break;  
  147.     case WM_PAINT:  
  148.         hdc = BeginPaint(hWnd, &ps);  
  149.         // TODO: Add any drawing code here...  
  150.         EndPaint(hWnd, &ps);  
  151.         break;  
  152.     case WM_DESTROY:  
  153.         PostQuitMessage(0);  
  154.         break;  
  155.     default:  
  156.         return DefWindowProc(hWnd, message, wParam, lParam);  
  157.     }  
  158.     return 0;  
  159. }  
  160.   
  161. // Message handler for about box.  
  162. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  163. {  
  164.     UNREFERENCED_PARAMETER(lParam);  
  165.     switch (message)  
  166.     {  
  167.     case WM_INITDIALOG:  
  168.         return (INT_PTR)TRUE;  
  169.   
  170.     case WM_COMMAND:  
  171.         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)  
  172.         {  
  173.             EndDialog(hDlg, LOWORD(wParam));  
  174.             return (INT_PTR)TRUE;  
  175.         }  
  176.         break;  
  177.     }  
  178.     return (INT_PTR)FALSE;  

We need the above code so we don't need to write a code for creating a window.

First add the OpenGL headers.
  1. #include<stdio.h>  
  2. #include<GL/gl.h>  
  3. #include<GL/glu.h> 
Then, we need to tell the compiler to link the OpenGL libraries.
  1. #pragma comment(lib, "opengl32.lib")  
  2. #pragma comment(lib, "glu32.lib") 
I'm also using the following variables to rotate the OpenGL objects.
  1. float angle = 0.0f;  
  2. float X_angle = 1.0f, Y_angle = 0.0f, Z_angle = 0.0f; 
Now, we have a window, so we need to create an OpenGL drawing surface on that window.

To do this, we need to set some pixel formats to that window.The pixel format will allow to enable the drawing of an OpenGL elements on it. First, declare the variable of PIXELFORMATDESCRIPTOR and set its fields. It has 26 fields. Most of the bits you can keep 0, but the flags, type, and size must be initialized.

Following is the function that returns the pixel format.
  1. //get pixel format descriptor   
  2. PIXELFORMATDESCRIPTOR GetPixelFormatDescriptor()  
  3. {  
  4.     PIXELFORMATDESCRIPTOR pfd;  
  5.   
  6.     pfd.bReserved = 0;  
  7.     pfd.cAccumAlphaBits = 0;  
  8.     pfd.cAccumBits = 0;  
  9.     pfd.cAccumBlueBits = 0;  
  10.     pfd.cAccumGreenBits = 0;  
  11.     pfd.cAccumRedBits = 0;  
  12.     pfd.cAlphaBits = 0;  
  13.     pfd.cAlphaShift = 0;  
  14.     pfd.cAuxBuffers = 0;  
  15.     pfd.cBlueBits = 0;  
  16.     pfd.cBlueShift = 0;  
  17.     pfd.cColorBits = 32;  
  18.     pfd.cDepthBits = 32;  
  19.     pfd.cGreenBits = 0;  
  20.     pfd.cGreenShift = 0;  
  21.     pfd.cRedBits = 0;  
  22.     pfd.cRedShift = 0;  
  23.     pfd.cStencilBits = 0;  
  24.     pfd.dwDamageMask = 0;  
  25.     pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;  
  26.     pfd.dwLayerMask = 0;  
  27.     pfd.dwVisibleMask = 0;  
  28.     pfd.iLayerType = 0;  
  29.     pfd.iPixelType = PFD_TYPE_RGBA;  
  30.     pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);  
  31.     pfd.nVersion = 1;  
  32.   
  33.     return pfd;  

The dwFlags are set to PFD_SUPPORT_OPENGL, to support OpenGL, PFD_DRAW_TO_WINDOW, drawing directly on a window rather than any other static control.

The iPixelType is of type RGBA.

Once we get our pixel format, we need to initialize our OpenGL on current window handler. To do this, we need the device context of the current window handler, same as we did in Basic Drawing.

Once you get the device context, get the pixel format descriptor by calling the above function. Choose the pixel format whether it supports the current device context or not by calling ChoosePixelFormat(HDC, PIXELFORMATDESCRIPTOR*) function.

If it supports, then set that pixel format using SetPixelFormat(HDC, int, PIXELFORMATDESCRIPTOR*) function to current device context by getting the pixel format by above function.

Now, you have a window that supports RGBA pixel formats. To create an OpenGL context surface for current device, call the wglCreateContext(HDC) function. wglCreateContext(HDC) returns the handle to the graphics library resource(HGLRC) from the provided device context. 

To enable the current device to support OpenGL, call wglMakeCurrent(HDC, HGLRC) function; it returns true or false values. Following is the function that initializes an OpenGL on current HWND.
  1. //initialize OpenGL  
  2. BOOL InitOpenGL(HWND hWnd)  
  3. {  
  4.     PIXELFORMATDESCRIPTOR pfd;  
  5.     int pixelFormat;  
  6.     HGLRC glrc;  
  7.     HDC hdc;  
  8.   
  9.     hdc = GetDC(hWnd);  
  10.   
  11.     if (hdc == NULL) {  
  12.         MessageBox(hWnd, TEXT("Error: Can't Get Device Context for Window"), TEXT("Error"),  
  13.                     MB_OK | MB_ICONERROR);  
  14.         return FALSE;  
  15.     }  
  16.   
  17.     pfd = GetPixelFormatDescriptor();  
  18.   
  19.     //choose pixel format for the current device context  
  20.     pixelFormat = ChoosePixelFormat(hdc, &pfd);  
  21.   
  22.     if (pixelFormat == 0) {  
  23.         MessageBox(hWnd, TEXT("Error: Can't Choose Pixel Format"), TEXT("Error"),   
  24.                     MB_OK | MB_ICONERROR);  
  25.         ReleaseDC(hWnd, hdc);  
  26.         return FALSE;  
  27.     }  
  28.   
  29.     //set pixel format for current device context  
  30.     pixelFormat = SetPixelFormat(hdc, pixelFormat, &pfd);  
  31.   
  32.     if (pixelFormat == 0) {  
  33.         MessageBox(hWnd, TEXT("Error: Can't Set The Pixel Format"), TEXT("Error"),   
  34.                     MB_OK | MB_ICONERROR);  
  35.         ReleaseDC(hWnd, hdc);  
  36.         return FALSE;  
  37.     }  
  38.       
  39.     //get handle to the GL of windows  
  40.     glrc = wglCreateContext(hdc);  
  41.   
  42.     if (glrc == NULL) {  
  43.         MessageBox(hWnd, TEXT("Error: Can't Create GL Context"), TEXT("Error"),   
  44.                     MB_OK | MB_ICONERROR);  
  45.         ReleaseDC(hWnd, hdc);  
  46.         return FALSE;  
  47.     }  
  48.   
  49.     //enable OpenGL for current device context  
  50.     if (!wglMakeCurrent(hdc, glrc)) {  
  51.         MessageBox(hWnd, TEXT("Error: Can't Make Current GL Context"), TEXT("Error"),   
  52.                     MB_OK | MB_ICONERROR);  
  53.         wglDeleteContext(glrc);  
  54.         ReleaseDC(hWnd, hdc);  
  55.         return FALSE;  
  56.     }  

To update the screen, we have used Reshape() function in GLUT. It's same as here, you just need to get the size of the window.
  1. //update matrix view by resizing a window   
  2. void GLResizeWindow(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  3. {  
  4.     RECT rect;  
  5.     GetClientRect(hwnd, &rect);  
  6.   
  7.     GLsizei width = rect.right - rect.left;  
  8.     GLsizei height = rect.bottom - rect.top;  
  9.   
  10.     glViewport(0, 0, width, height);  
  11.     gluPerspective(45, 1.0*(width/height), 1.0, 1000);  
  12.     glMatrixMode(GL_MODELVIEW);  
  13.     glLoadIdentity();  

We also used a texture in our OpenGL progams.
  1. //texture adder function  
  2. GLuint LoadTextureImageFile(const char * filename)  
  3. {  
  4.     GLuint texture = 0;  
  5.     int width, height;  
  6.     BYTE * data = NULL;  
  7.     FILE * file;  
  8.   
  9.     fopen_s(&file, filename, "rb");  
  10.   
  11.     if (&file == NULL) return 0;  
  12.   
  13.     width = 256;  
  14.     height = 256;  
  15.     data = (BYTE*)malloc(width * height * 3);  
  16.     fread(data, width * height * 3, 1, file);  
  17.     fclose(file);  
  18.     glGenTextures(1, &texture);  
  19.     glBindTexture(GL_TEXTURE_2D, texture);  
  20.     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_BGRA_EXT, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, data);  
  21.     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_TEXTURE_ENV_COLOR);  
  22.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  23.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
  24.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
  25.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);  
  26.     free(data);  
  27.     return texture;  
  28. }  
  29.   
  30. void FreeCreatedTexture(GLuint texture)  
  31. {  
  32.     glDeleteTextures(1, &texture);  

Here's the function that draws a simple component with textures,
  1. void DrawScene(HDC hdc)  
  2. {  
  3.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  4.     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  
  5.     glLoadIdentity();  
  6.   
  7.     glPushMatrix();  
  8.     glTranslatef(0.0f, 0.2f, 0.0f);  
  9.     glRotatef(angle, X_angle, Y_angle, Z_angle);  
  10.     glEnable(GL_TEXTURE_2D);  
  11.     glBindTexture(GL_TEXTURE_2D, LoadTextureImageFile("textures/blocks.bmp"));  
  12.   
  13.     glBegin(GL_QUADS);  
  14.     glTexCoord2f(0.0, 0.0);  
  15.     glVertex3f(-0.25f, 0.10f, 0.0f);  
  16.     glTexCoord2f(0.0, 1.0);  
  17.     glVertex3f(0.05f, 0.10f, 0.0f);  
  18.     glTexCoord2f(1.0, 1.0);  
  19.     glVertex3f(0.05f, -0.40f, 0.0f);  
  20.     glTexCoord2f(1.0, 0.0);  
  21.     glVertex3f(-0.25f, -0.40f, 0.0f);  
  22.     glEnd();  
  23.   
  24.     glBegin(GL_QUADS);  
  25.     glColor3f(0.8f, 0.8f, 0.8f);  
  26.     glTexCoord2f(0.0, 0.0);  
  27.     glVertex3f(-0.25f, 0.10f, 0.0f);  
  28.     glTexCoord2f(0.0, 1.0);  
  29.     glVertex3f(-0.25f, 0.10f, 0.30f);  
  30.     glTexCoord2f(1.0, 1.0);  
  31.     glVertex3f(-0.25f, -0.40f, 0.30f);  
  32.     glTexCoord2f(1.0, 0.0);  
  33.     glVertex3f(-0.25f, -0.40f, 0.0f);  
  34.     glEnd();  
  35.   
  36.     glBegin(GL_QUADS);  
  37.     glTexCoord2f(0.0, 0.0);  
  38.     glVertex3f(0.05f, 0.10f, 0.0f);  
  39.     glTexCoord2f(0.0, 1.0);  
  40.     glVertex3f(0.05f, 0.10f, 0.30f);  
  41.     glTexCoord2f(1.0, 1.0);  
  42.     glVertex3f(0.05f, -0.40f, 0.30f);  
  43.     glTexCoord2f(1.0, 0.0);  
  44.     glVertex3f(0.05f, -0.40f, 0.0f);  
  45.     glEnd();  
  46.   
  47.     glBegin(GL_QUADS);  
  48.     glTexCoord2f(0.0, 0.0);  
  49.     glVertex3f(-0.25f, 0.10f, 0.0f);  
  50.     glTexCoord2f(0.0, 1.0);  
  51.     glVertex3f(0.05f, 0.10f, 0.0f);  
  52.     glTexCoord2f(1.0, 1.0);  
  53.     glVertex3f(0.05f, 0.10f, 0.30f);  
  54.     glTexCoord2f(1.0, 0.0);  
  55.     glVertex3f(-0.25f, 0.10f, 0.30f);  
  56.     glEnd();  
  57.   
  58.     glBegin(GL_QUADS);  
  59.     glTexCoord2f(0.0, 0.0);  
  60.     glVertex3f(-0.25f, -0.40f, 0.0f);  
  61.     glTexCoord2f(0.0, 1.0);  
  62.     glVertex3f(0.05f, -0.40f, 0.0f);  
  63.     glTexCoord2f(1.0, 1.0);  
  64.     glVertex3f(0.05f, -0.40f, 0.30f);  
  65.     glTexCoord2f(1.0, 0.0);  
  66.     glVertex3f(-0.25f, -0.40f, 0.30f);  
  67.     glEnd();  
  68.   
  69.     glPopMatrix();  
  70.     glDisable(GL_TEXTURE_2D);  
  71.   
  72.     glEnable(GL_TEXTURE_2D);  
  73.     glBindTexture(GL_TEXTURE_2D, LoadTextureImageFile("textures/rocks.bmp"));  
  74.     glPushMatrix();  
  75.     glTranslatef(-0.5f, 0.4f, 0.0f);  
  76.     glRotatef(angle, X_angle, Y_angle, Z_angle);  
  77.     glBegin(GL_TRIANGLES);  
  78.     glColor3f(1.0f, 1.0f, 1.0f);  
  79.     glTexCoord2f(0.0, 0.0);  
  80.     glVertex3f(0.0f, 0.3f, 0.0f);  
  81.     glTexCoord2f(0.0, 1.0);  
  82.     glVertex3f(0.15f, -0.1f, 0.0f);  
  83.     glTexCoord2f(1.0, 1.0);  
  84.     glVertex3f(-0.15f, -0.1f, 0.0f);  
  85.     glEnd();  
  86.   
  87.     glPopMatrix();  
  88.     glDisable(GL_TEXTURE_2D);  
  89.   
  90.     GLUquadric *quad = gluNewQuadric();  
  91.     glEnable(GL_TEXTURE_2D);  
  92.     glBindTexture(GL_TEXTURE_2D, LoadTextureImageFile("textures/blocks5.bmp"));  
  93.     gluQuadricTexture(quad, 1);  
  94.     glPushMatrix();  
  95.     glTranslatef(0.4f, 0.5f, 0.0f);  
  96.     glRotatef(angle, X_angle, Y_angle, Z_angle);  
  97.     glColor3f(1.0f, 1.0f, 1.0f);  
  98.     gluCylinder(quad, 0.1f, 0.1f, 0.6f, 40, 40);  
  99.     glPopMatrix();  
  100.     glDisable(GL_TEXTURE_2D);  
  101.   
  102.     GLUquadric *quad2 = gluNewQuadric();  
  103.     glEnable(GL_TEXTURE_2D);  
  104.     glBindTexture(GL_TEXTURE_2D, LoadTextureImageFile("textures/blocks8.bmp"));  
  105.     gluQuadricTexture(quad2, 1);  
  106.     glPushMatrix();  
  107.     glTranslatef(0.4f, -0.5f, 0.0f);  
  108.     glRotatef(angle, X_angle, Y_angle, Z_angle);  
  109.     glColor3f(1.0f, 1.0f, 1.0f);  
  110.     gluCylinder(quad2, 0.1f, 0.1f, 0.6f, 40, 40);  
  111.     glPopMatrix();  
  112.     glDisable(GL_TEXTURE_2D);  
  113.   
  114.     SwapBuffers(hdc);  

In _tWinMain() function, call the DrawScene() function in message loop.
  1. // Main message loop:  
  2. while (GetMessage(&msg, NULL, 0, 0))  
  3. {  
  4.     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))  
  5.     {  
  6.         //draw a scene on a window  
  7.         DrawScene(GetDC(mainHWND));  
  8.   
  9.         TranslateMessage(&msg);  
  10.         DispatchMessage(&msg);  
  11.     }  

To initialize OpenGL for current window, create a WM_CREATE case statement in the function WndProc() and call the above InitOpenGL() function.

You can also do this by calling in WM_PAINT and not in WM_CREATE. Also create WM_SIZE case and call GLResizeWindow() function in it.
  1. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     int wmId, wmEvent;  
  4.     PAINTSTRUCT ps;  
  5.     HDC hdc;  
  6.   
  7.     switch (message)  
  8.     {  
  9.     case WM_CREATE :  
  10.         if (!InitOpenGL(hWnd)){  
  11.             MessageBox(hWnd, TEXT("Error: Cannot initialize OpenGL"), TEXT("ERROR"),  
  12.                 MB_OK | MB_ICONERROR);  
  13.         }  
  14.         break;  
  15.   
  16.     case WM_COMMAND:  
  17.         wmId    = LOWORD(wParam);  
  18.         wmEvent = HIWORD(wParam);  
  19.         // Parse the menu selections:  
  20.         switch (wmId)  
  21.         {  
  22.         case IDM_ABOUT:  
  23.             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);  
  24.             break;  
  25.         case IDM_EXIT:  
  26.             DestroyWindow(hWnd);  
  27.             break;  
  28.         default:  
  29.             return DefWindowProc(hWnd, message, wParam, lParam);  
  30.         }  
  31.         break;  
  32.   
  33.     case WM_KEYDOWN:  
  34.         switch (wParam)  
  35.         {  
  36.         case VK_DOWN :  
  37.             angle += 3.0f;  
  38.             X_angle = 1.0f;  
  39.             Y_angle = 0.0f;  
  40.             Z_angle = 0.0f;  
  41.             break;  
  42.         case VK_RIGHT :  
  43.             angle += 3.0f;  
  44.             X_angle = 0.0f;  
  45.             Y_angle = 1.0f;  
  46.             Z_angle = 0.0f;  
  47.             break;  
  48.         case VK_LEFT:  
  49.             angle += 3.0f;  
  50.             X_angle = 0.0f;  
  51.             Y_angle = 0.0f;  
  52.             Z_angle = 1.0f;  
  53.             break;  
  54.         case VK_UP:  
  55.             angle += 3.0f;  
  56.             X_angle = 1.0f;  
  57.             Y_angle = 1.0f;  
  58.             Z_angle = 1.0f;  
  59.             break;  
  60.         }  
  61.         break;  
  62.   
  63.     case WM_SIZE:  
  64.         GLResizeWindow(hWnd, message, wParam, lParam);  
  65.         break;  
  66.   
  67.     case WM_PAINT:  
  68.         hdc = BeginPaint(hWnd, &ps);  
  69.         // TODO: Add any drawing code here...  
  70.         EndPaint(hWnd, &ps);  
  71.         break;  
  72.     case WM_DESTROY:  
  73.         PostQuitMessage(0);  
  74.         break;  
  75.     default:  
  76.         return DefWindowProc(hWnd, message, wParam, lParam);  
  77.     }  
  78.     return 0;  
  79. }  


Similar Articles