home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible / OpenGL_Superbible_Waite_Group_Press_1996.iso / book / chapt10 / thread / thread.c < prev    next >
C/C++ Source or Header  |  1996-07-06  |  19KB  |  698 lines

  1. // Thread.c
  2. // Draws just the thread of the bolt
  3.  
  4. #include <windows.h>            // Window defines
  5. #include <gl\gl.h>              // OpenGL
  6. #include <gl\glu.h>             // GLU library
  7. #include <math.h>                // Define for trig funcs.
  8. #include "resource.h"           // About box resource identifiers.
  9.  
  10.  
  11. HPALETTE hPalette = NULL;
  12.  
  13. // Application name and instance storeage
  14. static LPCTSTR lpszAppName = "Bolt Thread";
  15. static HINSTANCE hInstance;
  16.  
  17. // Rotation amounts
  18. static GLfloat xRot = 0.0f;
  19. static GLfloat yRot = 0.0f;
  20.  
  21. // Declaration for Window procedure
  22. LRESULT CALLBACK WndProc(   HWND    hWnd,
  23.                             UINT    message,
  24.                             WPARAM  wParam,
  25.                             LPARAM  lParam);
  26.  
  27. // Dialog procedure for about box
  28. BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);
  29.  
  30. // Set Pixel Format function - forward declaration
  31. void SetDCPixelFormat(HDC hDC);
  32.  
  33.  
  34.  
  35. // Reduces a normal vector specified as a set of three coordinates,
  36. // to a unit normal vector of length one.
  37. void ReduceToUnit(float vector[3])
  38.     {
  39.     float length;
  40.     
  41.     // Calculate the length of the vector        
  42.     length = (float)sqrt((vector[0]*vector[0]) + 
  43.                         (vector[1]*vector[1]) +
  44.                         (vector[2]*vector[2]));
  45.  
  46.     // Keep the program from blowing up by providing an exceptable
  47.     // value for vectors that may calculated too close to zero.
  48.     if(length == 0.0f)
  49.         length = 1.0f;
  50.  
  51.     // Dividing each element by the length will result in a
  52.     // unit normal vector.
  53.     vector[0] /= length;
  54.     vector[1] /= length;
  55.     vector[2] /= length;
  56.     }
  57.  
  58.  
  59. // Points p1, p2, & p3 specified in counter clock-wise order
  60. void calcNormal(float v[3][3], float out[3])
  61.     {
  62.     float v1[3],v2[3];
  63.     static const int x = 0;
  64.     static const int y = 1;
  65.     static const int z = 2;
  66.  
  67.     // Calculate two vectors from the three points
  68.     v1[x] = v[0][x] - v[1][x];
  69.     v1[y] = v[0][y] - v[1][y];
  70.     v1[z] = v[0][z] - v[1][z];
  71.  
  72.     v2[x] = v[1][x] - v[2][x];
  73.     v2[y] = v[1][y] - v[2][y];
  74.     v2[z] = v[1][z] - v[2][z];
  75.  
  76.     // Take the cross product of the two vectors to get
  77.     // the normal vector which will be stored in out
  78.     out[x] = v1[y]*v2[z] - v1[z]*v2[y];
  79.     out[y] = v1[z]*v2[x] - v1[x]*v2[z];
  80.     out[z] = v1[x]*v2[y] - v1[y]*v2[x];
  81.  
  82.     // Normalize the vector (shorten length to one)
  83.     ReduceToUnit(out);
  84.     }
  85.  
  86.  
  87.  
  88. // Change viewing volume and viewport.  Called when window is resized
  89. void ChangeSize(GLsizei w, GLsizei h)
  90.     {
  91.     GLfloat nRange = 100.0f;
  92.  
  93.     // Prevent a divide by zero
  94.     if(h == 0)
  95.         h = 1;
  96.  
  97.  
  98.     // Set Viewport to window dimensions
  99.     glViewport(0, 0, w, h);
  100.  
  101.     // Reset coordinate system
  102.     glMatrixMode(GL_PROJECTION);
  103.     glLoadIdentity();
  104.  
  105.     // Establish clipping volume (left, right, bottom, top, near, far)
  106.     if (w <= h) 
  107.         glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange*2.0f, nRange*2.0f);
  108.     else 
  109.         glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange*2.0f, nRange*2.0f);
  110.  
  111.     glMatrixMode(GL_MODELVIEW);
  112.     glLoadIdentity();
  113.     }
  114.  
  115.  
  116.  
  117. // This function does any needed initialization on the rendering
  118. // context.  Here it sets up and initializes the lighting for
  119. // the scene.
  120. void SetupRC()
  121.     {
  122.     // Light values and coordinates
  123.     GLfloat  ambientLight[] = {0.4f, 0.4f, 0.4f, 1.0f };
  124.     GLfloat  diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f };
  125.     GLfloat  specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
  126.     GLfloat     lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
  127.     GLfloat  specref[] =  { 0.6f, 0.6f, 0.6f, 1.0f };
  128.  
  129.  
  130.     glEnable(GL_DEPTH_TEST);    // Hidden surface removal
  131.     glEnable(GL_CULL_FACE);        // Do not calculate inside of solid object
  132.     
  133.     // Enable lighting
  134.     glEnable(GL_LIGHTING);
  135.  
  136.     // Setup light 0
  137.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
  138.     glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
  139.     glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
  140.     glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
  141.  
  142.     // Position and turn on the light
  143.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  144.     glEnable(GL_LIGHT0);
  145.  
  146.     // Enable color tracking
  147.     glEnable(GL_COLOR_MATERIAL);
  148.     
  149.     // Set Material properties to follow glColor values
  150.     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  151.  
  152.     // All materials hereafter have full specular reflectivity
  153.     // with a moderate shine
  154.     glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
  155.     glMateriali(GL_FRONT,GL_SHININESS,64);
  156.  
  157.     // Black background
  158.     glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
  159.     }
  160.  
  161.  
  162. // Creates the head of the bolt
  163. void RenderThread(void)
  164.     {
  165.     float x,y,z,angle;                // Calculate coordinates and step angle
  166.     float height = 75.0f;            // Height of the threading
  167.     float diameter = 20.0f;            // Diameter of the threading
  168.     float normal[3],corners[4][3];    // Storeage for calculate normal and corners
  169.     float step = (3.1415f/32.0f);    // one revolution
  170.     float revolutions = 7.0f;        // How many time around the shaft
  171.     float threadWidth = 2.0f;        // How wide is the thread
  172.     float threadThick = 3.0f;        // How thick is the thread
  173.     float zstep = .125f;            // How much does the thread move up
  174.                                     // the Z axis each time a new segment
  175.                                     // is drawn.
  176.  
  177.     // 360 degrees in radians
  178.     #define PI2 (2.0f*3.1415f)
  179.  
  180.     // Set material color for thread
  181.     glColor3f(0.0f, 0.0f, 0.4f);    
  182.         
  183.  
  184.     z = -height+2;    // Starting spot almost to the end
  185.  
  186.     // Go around and draw the sides until finished spinning up
  187.     for(angle = 0.0f; angle < PI2*revolutions; angle += step)
  188.         {
  189.         // Calculate x and y position of the next vertex
  190.         x = diameter*(float)sin(angle);
  191.         y = diameter*(float)cos(angle);
  192.     
  193.         // Store the next vertex next to the shaft
  194.         corners[0][0] = x;
  195.         corners[0][1] = y;
  196.         corners[0][2] = z;
  197.  
  198.         // Calculate the position away from the shaft
  199.         x = (diameter+threadWidth)*(float)sin(angle);
  200.         y = (diameter+threadWidth)*(float)cos(angle);
  201.  
  202.         corners[1][0] = x;
  203.         corners[1][1] = y;
  204.         corners[1][2] = z;
  205.  
  206.         // Calculate the next position away from the shaft
  207.         x = (diameter+threadWidth)*(float)sin(angle+step);
  208.         y = (diameter+threadWidth)*(float)cos(angle+step);
  209.  
  210.         corners[2][0] = x;
  211.         corners[2][1] = y;
  212.         corners[2][2] = z + zstep;
  213.  
  214.         // Calculate the next position along the shaft
  215.         x = (diameter)*(float)sin(angle+step);
  216.         y = (diameter)*(float)cos(angle+step);
  217.  
  218.         corners[3][0] = x;
  219.         corners[3][1] = y;
  220.         corners[3][2] = z+ zstep;
  221.     
  222.  
  223.         // We'll be using triangels, so make 
  224.         // counter clock-wise polygons face out
  225.         glFrontFace(GL_CCW);        
  226.         glBegin(GL_TRIANGLES);    // Start the top section of thread
  227.  
  228.             // Calculate the normal for this segment
  229.             calcNormal(corners, normal);
  230.             glNormal3fv(normal);
  231.  
  232.             // Draw two triangles to cover area
  233.             glVertex3fv(corners[0]);
  234.             glVertex3fv(corners[1]);
  235.             glVertex3fv(corners[2]);
  236.  
  237.             glVertex3fv(corners[2]);
  238.             glVertex3fv(corners[3]);
  239.             glVertex3fv(corners[0]);
  240.  
  241.         glEnd();
  242.  
  243.  
  244.         // Move the edge along the shaft slightly up the z axis
  245.         // to represent the bottom of the thread
  246.         corners[0][2] += threadThick;
  247.         corners[3][2] += threadThick;
  248.  
  249.         // Recalculate the normal since points have changed, this
  250.         // time it points in the opposite direction, so reverse it
  251.         calcNormal(corners, normal);
  252.         normal[0] = -normal[0];
  253.         normal[1] = -normal[1];
  254.         normal[2] = -normal[2];
  255.                 
  256.         // Switch to clock-wise facing out for underside of the
  257.         // thread.
  258.         glFrontFace(GL_CW);
  259.  
  260.         // Draw the two triangles
  261.         glBegin(GL_TRIANGLES);
  262.             glNormal3fv(normal);
  263.  
  264.             glVertex3fv(corners[0]);
  265.             glVertex3fv(corners[1]);
  266.             glVertex3fv(corners[2]);
  267.  
  268.             glVertex3fv(corners[2]);
  269.             glVertex3fv(corners[3]);
  270.             glVertex3fv(corners[0]);
  271.  
  272.         glEnd();
  273.  
  274.         // Creep up the Z axis
  275.         z += zstep;
  276.         }
  277.     }
  278.  
  279.  
  280.  
  281. // Called to draw scene
  282. void RenderScene(void)
  283.     {
  284.     // Clear the window with current clearing color
  285.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  286.  
  287.     // Save the matrix state
  288.     glMatrixMode(GL_MODELVIEW);
  289.     glPushMatrix();
  290.     
  291.     // Rotate about x and y axes
  292.     glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  293.     glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  294.  
  295.     // Render just the hexagonial head of the nut
  296.     RenderThread();
  297.  
  298.     glPopMatrix();
  299.  
  300.     // Flush drawing commands
  301.     glFlush();
  302.     }
  303.  
  304.  
  305. // Select the pixel format for a given device context
  306. void SetDCPixelFormat(HDC hDC)
  307.     {
  308.     int nPixelFormat;
  309.  
  310.     static PIXELFORMATDESCRIPTOR pfd = {
  311.         sizeof(PIXELFORMATDESCRIPTOR),  // Size of this structure
  312.         1,                                                              // Version of this structure    
  313.         PFD_DRAW_TO_WINDOW |                    // Draw to Window (not to bitmap)
  314.         PFD_SUPPORT_OPENGL |                    // Support OpenGL calls in window
  315.         PFD_DOUBLEBUFFER,                       // Double buffered
  316.         PFD_TYPE_RGBA,                          // RGBA Color mode
  317.         24,                                     // Want 24bit color 
  318.         0,0,0,0,0,0,                            // Not used to select mode
  319.         0,0,                                    // Not used to select mode
  320.         0,0,0,0,0,                              // Not used to select mode
  321.         32,                                     // Size of depth buffer
  322.         0,                                      // Not used to select mode
  323.         0,                                      // Not used to select mode
  324.         PFD_MAIN_PLANE,                         // Draw in main plane
  325.         0,                                      // Not used to select mode
  326.         0,0,0 };                                // Not used to select mode
  327.  
  328.     // Choose a pixel format that best matches that described in pfd
  329.     nPixelFormat = ChoosePixelFormat(hDC, &pfd);
  330.  
  331.     // Set the pixel format for the device context
  332.     SetPixelFormat(hDC, nPixelFormat, &pfd);
  333.     }
  334.  
  335.  
  336.  
  337. // If necessary, creates a 3-3-2 palette for the device context listed.
  338. HPALETTE GetOpenGLPalette(HDC hDC)
  339.     {
  340.     HPALETTE hRetPal = NULL;    // Handle to palette to be created
  341.     PIXELFORMATDESCRIPTOR pfd;    // Pixel Format Descriptor
  342.     LOGPALETTE *pPal;            // Pointer to memory for logical palette
  343.     int nPixelFormat;            // Pixel format index
  344.     int nColors;                // Number of entries in palette
  345.     int i;                        // Counting variable
  346.     BYTE RedRange,GreenRange,BlueRange;
  347.                                 // Range for each color entry (7,7,and 3)
  348.  
  349.  
  350.     // Get the pixel format index and retrieve the pixel format description
  351.     nPixelFormat = GetPixelFormat(hDC);
  352.     DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
  353.  
  354.     // Does this pixel format require a palette?  If not, do not create a
  355.     // palette and just return NULL
  356.     if(!(pfd.dwFlags & PFD_NEED_PALETTE))
  357.         return NULL;
  358.  
  359.     // Number of entries in palette.  8 bits yeilds 256 entries
  360.     nColors = 1 << pfd.cColorBits;    
  361.  
  362.     // Allocate space for a logical palette structure plus all the palette entries
  363.     pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));
  364.  
  365.     // Fill in palette header 
  366.     pPal->palVersion = 0x300;        // Windows 3.0
  367.     pPal->palNumEntries = nColors; // table size
  368.  
  369.     // Build mask of all 1's.  This creates a number represented by having
  370.     // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
  371.     // pfd.cBlueBits.  
  372.     RedRange = (1 << pfd.cRedBits) -1;
  373.     GreenRange = (1 << pfd.cGreenBits) - 1;
  374.     BlueRange = (1 << pfd.cBlueBits) -1;
  375.  
  376.     // Loop through all the palette entries
  377.     for(i = 0; i < nColors; i++)
  378.         {
  379.         // Fill in the 8-bit equivalents for each component
  380.         pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
  381.         pPal->palPalEntry[i].peRed = (unsigned char)(
  382.             (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);
  383.  
  384.         pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
  385.         pPal->palPalEntry[i].peGreen = (unsigned char)(
  386.             (double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
  387.  
  388.         pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
  389.         pPal->palPalEntry[i].peBlue = (unsigned char)(
  390.             (double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
  391.  
  392.         pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
  393.         }
  394.         
  395.  
  396.     // Create the palette
  397.     hRetPal = CreatePalette(pPal);
  398.  
  399.     // Go ahead and select and realize the palette for this device context
  400.     SelectPalette(hDC,hRetPal,FALSE);
  401.     RealizePalette(hDC);
  402.  
  403.     // Free the memory used for the logical palette structure
  404.     free(pPal);
  405.  
  406.     // Return the handle to the new palette
  407.     return hRetPal;
  408.     }
  409.  
  410.  
  411. // Entry point of all Windows programs
  412. int APIENTRY WinMain(   HINSTANCE       hInst,
  413.                         HINSTANCE       hPrevInstance,
  414.                         LPSTR           lpCmdLine,
  415.                         int                     nCmdShow)
  416.     {
  417.     MSG                     msg;            // Windows message structure
  418.     WNDCLASS        wc;                     // Windows class structure
  419.     HWND            hWnd;           // Storeage for window handle
  420.  
  421.     hInstance = hInst;
  422.  
  423.     // Register Window style
  424.     wc.style                        = CS_HREDRAW | CS_VREDRAW;
  425.     wc.lpfnWndProc          = (WNDPROC) WndProc;
  426.     wc.cbClsExtra           = 0;
  427.     wc.cbWndExtra           = 0;
  428.     wc.hInstance            = hInstance;
  429.     wc.hIcon                        = NULL;
  430.     wc.hCursor                      = LoadCursor(NULL, IDC_ARROW);
  431.     
  432.     // No need for background brush for OpenGL window
  433.     wc.hbrBackground        = NULL;         
  434.     
  435.     wc.lpszMenuName         = MAKEINTRESOURCE(IDR_MENU);
  436.     wc.lpszClassName        = lpszAppName;
  437.  
  438.     // Register the window class
  439.     if(RegisterClass(&wc) == 0)
  440.         return FALSE;
  441.  
  442.  
  443.     // Create the main application window
  444.     hWnd = CreateWindow(
  445.                 lpszAppName,
  446.                 lpszAppName,
  447.                 
  448.                 // OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
  449.                 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  450.     
  451.                 // Window position and size
  452.                 50, 50,
  453.                 400, 400,
  454.                 NULL,
  455.                 NULL,
  456.                 hInstance,
  457.                 NULL);
  458.  
  459.     // If window was not created, quit
  460.     if(hWnd == NULL)
  461.         return FALSE;
  462.  
  463.  
  464.     // Display the window
  465.     ShowWindow(hWnd,SW_SHOW);
  466.     UpdateWindow(hWnd);
  467.  
  468.     // Process application messages until the application closes
  469.     while( GetMessage(&msg, NULL, 0, 0))
  470.         {
  471.         TranslateMessage(&msg);
  472.         DispatchMessage(&msg);
  473.         }
  474.  
  475.     return msg.wParam;
  476.     }
  477.  
  478.  
  479.  
  480.  
  481. // Window procedure, handles all messages for this program
  482. LRESULT CALLBACK WndProc(       HWND    hWnd,
  483.                             UINT    message,
  484.                             WPARAM  wParam,
  485.                             LPARAM  lParam)
  486.     {
  487.     static HGLRC hRC;               // Permenant Rendering context
  488.     static HDC hDC;                 // Private GDI Device context
  489.  
  490.     switch (message)
  491.         {
  492.         // Window creation, setup for OpenGL
  493.         case WM_CREATE:
  494.             // Store the device context
  495.             hDC = GetDC(hWnd);              
  496.  
  497.             // Select the pixel format
  498.             SetDCPixelFormat(hDC);          
  499.  
  500.             hPalette = GetOpenGLPalette(hDC);
  501.  
  502.             // Create the rendering context and make it current
  503.             hRC = wglCreateContext(hDC);
  504.             wglMakeCurrent(hDC, hRC);
  505.             SetupRC();
  506.  
  507.             break;
  508.  
  509.         // Window is being destroyed, cleanup
  510.         case WM_DESTROY:
  511.             // Deselect the current rendering context and delete it
  512.             wglMakeCurrent(hDC,NULL);
  513.             wglDeleteContext(hRC);
  514.  
  515.             if(hPalette != NULL)
  516.                 DeleteObject(hPalette);
  517.  
  518.             // Tell the application to terminate after the window
  519.             // is gone.
  520.             PostQuitMessage(0);
  521.             break;
  522.  
  523.         // Window is resized.
  524.         case WM_SIZE:
  525.             // Call our function which modifies the clipping
  526.             // volume and viewport
  527.             ChangeSize(LOWORD(lParam), HIWORD(lParam));
  528.             break;
  529.  
  530.  
  531.         // The painting function.  This message sent by Windows 
  532.         // whenever the screen needs updating.
  533.         case WM_PAINT:
  534.             {
  535.             // Call OpenGL drawing code
  536.             RenderScene();
  537.  
  538.             SwapBuffers(hDC);
  539.  
  540.             // Validate the newly painted client area
  541.             ValidateRect(hWnd,NULL);
  542.             }
  543.             break;
  544.  
  545.         // Windows is telling the application that it may modify
  546.         // the system palette.  This message in essance asks the 
  547.         // application for a new palette.
  548.         case WM_QUERYNEWPALETTE:
  549.             // If the palette was created.
  550.             if(hPalette)
  551.                 {
  552.                 int nRet;
  553.  
  554.                 // Selects the palette into the current device context
  555.                 SelectPalette(hDC, hPalette, FALSE);
  556.  
  557.                 // Map entries from the currently selected palette to
  558.                 // the system palette.  The return value is the number 
  559.                 // of palette entries modified.
  560.                 nRet = RealizePalette(hDC);
  561.  
  562.                 // Repaint, forces remap of palette in current window
  563.                 InvalidateRect(hWnd,NULL,FALSE);
  564.  
  565.                 return nRet;
  566.                 }
  567.             break;
  568.  
  569.     
  570.         // This window may set the palette, even though it is not the 
  571.         // currently active window.
  572.         case WM_PALETTECHANGED:
  573.             // Don't do anything if the palette does not exist, or if
  574.             // this is the window that changed the palette.
  575.             if((hPalette != NULL) && ((HWND)wParam != hWnd))
  576.                 {
  577.                 // Select the palette into the device context
  578.                 SelectPalette(hDC,hPalette,FALSE);
  579.  
  580.                 // Map entries to system palette
  581.                 RealizePalette(hDC);
  582.                 
  583.                 // Remap the current colors to the newly realized palette
  584.                 UpdateColors(hDC);
  585.                 return 0;
  586.                 }
  587.             break;
  588.  
  589.         // Key press, check for arrow keys to do cube rotation.
  590.         case WM_KEYDOWN:
  591.             {
  592.             if(wParam == VK_UP)
  593.                 xRot-= 5.0f;
  594.  
  595.             if(wParam == VK_DOWN)
  596.                 xRot += 5.0f;
  597.  
  598.             if(wParam == VK_LEFT)
  599.                 yRot -= 5.0f;
  600.  
  601.             if(wParam == VK_RIGHT)
  602.                 yRot += 5.0f;
  603.  
  604.             xRot = (float)((const int)xRot % 360);
  605.             yRot = (float)((const int)yRot % 360);
  606.  
  607.             InvalidateRect(hWnd,NULL,FALSE);
  608.             }
  609.             break;
  610.  
  611.         // A menu command
  612.         case WM_COMMAND:
  613.             {
  614.             switch(LOWORD(wParam))
  615.                 {
  616.                 // Exit the program
  617.                 case ID_FILE_EXIT:
  618.                     DestroyWindow(hWnd);
  619.                     break;
  620.  
  621.                 // Display the about box
  622.                 case ID_HELP_ABOUT:
  623.                     DialogBox (hInstance,
  624.                         MAKEINTRESOURCE(IDD_DIALOG_ABOUT),
  625.                         hWnd,
  626.                         AboutDlgProc);
  627.                     break;
  628.                 }
  629.             }
  630.             break;
  631.  
  632.  
  633.     default:   // Passes it on if unproccessed
  634.         return (DefWindowProc(hWnd, message, wParam, lParam));
  635.  
  636.     }
  637.  
  638.     return (0L);
  639.     }
  640.  
  641.  
  642.  
  643.  
  644. // Dialog procedure.
  645. BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam)
  646.     {
  647.     
  648.     switch (message)
  649.     {
  650.         // Initialize the dialog box
  651.         case WM_INITDIALOG:
  652.             {
  653.             int i;
  654.             GLenum glError;
  655.  
  656.             // glGetString demo
  657.             SetDlgItemText(hDlg,IDC_OPENGL_VENDOR,glGetString(GL_VENDOR));
  658.             SetDlgItemText(hDlg,IDC_OPENGL_RENDERER,glGetString(GL_RENDERER));
  659.             SetDlgItemText(hDlg,IDC_OPENGL_VERSION,glGetString(GL_VERSION));
  660.             SetDlgItemText(hDlg,IDC_OPENGL_EXTENSIONS,glGetString(GL_EXTENSIONS));
  661.  
  662.             // gluGetString demo
  663.             SetDlgItemText(hDlg,IDC_GLU_VERSION,gluGetString(GLU_VERSION));
  664.             SetDlgItemText(hDlg,IDC_GLU_EXTENSIONS,gluGetString(GLU_EXTENSIONS));
  665.  
  666.  
  667.             // Display any recent error messages
  668.             i = 0;
  669.             do {
  670.                 glError = glGetError();
  671.                 SetDlgItemText(hDlg,IDC_ERROR1+i,gluErrorString(glError));
  672.                 i++;
  673.                 }
  674.             while(i < 6 && glError != GL_NO_ERROR);
  675.  
  676.  
  677.             return (TRUE);
  678.             }
  679.             break;
  680.  
  681.         // Process command messages
  682.         case WM_COMMAND:      
  683.             {
  684.             // Validate and Make the changes
  685.             if(LOWORD(wParam) == IDOK)
  686.                 EndDialog(hDlg,TRUE);
  687.             }
  688.             break;
  689.  
  690.         // Closed from sysbox
  691.         case WM_CLOSE:
  692.             EndDialog(hDlg,TRUE);
  693.             break;
  694.         }
  695.  
  696.     return FALSE;
  697.     }
  698.