home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible / OpenGL_Superbible_Waite_Group_Press_1996.iso / book / chapt10 / boltlist / boltlist.c next >
C/C++ Source or Header  |  1996-07-05  |  28KB  |  1,036 lines

  1. // Boltlist.c
  2. // Draws the entire bolt using a display list
  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 = "Display List Bolt";
  15. static HINSTANCE hInstance;
  16.  
  17. // Rotation amounts
  18. static GLfloat xRot = 0.0f;
  19. static GLfloat yRot = 0.0f;
  20.  
  21. #define BOLT_HEAD    1
  22. #define BOLT_SHAFT    2
  23. #define BOLT_THREAD 3
  24.  
  25. // Declaration for Window procedure
  26. LRESULT CALLBACK WndProc(   HWND    hWnd,
  27.                             UINT    message,
  28.                             WPARAM  wParam,
  29.                             LPARAM  lParam);
  30.  
  31. // Dialog procedure for about box
  32. BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);
  33.  
  34. // Set Pixel Format function - forward declaration
  35. void SetDCPixelFormat(HDC hDC);
  36.  
  37.  
  38.  
  39. // Reduces a normal vector specified as a set of three coordinates,
  40. // to a unit normal vector of length one.
  41. void ReduceToUnit(float vector[3])
  42.     {
  43.     float length;
  44.     
  45.     // Calculate the length of the vector        
  46.     length = (float)sqrt((vector[0]*vector[0]) + 
  47.                         (vector[1]*vector[1]) +
  48.                         (vector[2]*vector[2]));
  49.  
  50.     // Keep the program from blowing up by providing an exceptable
  51.     // value for vectors that may calculated too close to zero.
  52.     if(length == 0.0f)
  53.         length = 1.0f;
  54.  
  55.     // Dividing each element by the length will result in a
  56.     // unit normal vector.
  57.     vector[0] /= length;
  58.     vector[1] /= length;
  59.     vector[2] /= length;
  60.     }
  61.  
  62.  
  63. // Points p1, p2, & p3 specified in counter clock-wise order
  64. void calcNormal(float v[3][3], float out[3])
  65.     {
  66.     float v1[3],v2[3];
  67.     static const int x = 0;
  68.     static const int y = 1;
  69.     static const int z = 2;
  70.  
  71.     // Calculate two vectors from the three points
  72.     v1[x] = v[0][x] - v[1][x];
  73.     v1[y] = v[0][y] - v[1][y];
  74.     v1[z] = v[0][z] - v[1][z];
  75.  
  76.     v2[x] = v[1][x] - v[2][x];
  77.     v2[y] = v[1][y] - v[2][y];
  78.     v2[z] = v[1][z] - v[2][z];
  79.  
  80.     // Take the cross product of the two vectors to get
  81.     // the normal vector which will be stored in out
  82.     out[x] = v1[y]*v2[z] - v1[z]*v2[y];
  83.     out[y] = v1[z]*v2[x] - v1[x]*v2[z];
  84.     out[z] = v1[x]*v2[y] - v1[y]*v2[x];
  85.  
  86.     // Normalize the vector (shorten length to one)
  87.     ReduceToUnit(out);
  88.     }
  89.  
  90.  
  91.  
  92. // Change viewing volume and viewport.  Called when window is resized
  93. void ChangeSize(GLsizei w, GLsizei h)
  94.     {
  95.     GLfloat nRange = 100.0f;
  96.  
  97.     // Prevent a divide by zero
  98.     if(h == 0)
  99.         h = 1;
  100.  
  101.  
  102.     // Set Viewport to window dimensions
  103.     glViewport(0, 0, w, h);
  104.  
  105.     // Reset coordinate system
  106.     glMatrixMode(GL_PROJECTION);
  107.     glLoadIdentity();
  108.  
  109.     // Establish clipping volume (left, right, bottom, top, near, far)
  110.     if (w <= h) 
  111.         glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange*2.0f, nRange*2.0f);
  112.     else 
  113.         glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange*2.0f, nRange*2.0f);
  114.  
  115.     glMatrixMode(GL_MODELVIEW);
  116.     glLoadIdentity();
  117.     }
  118.  
  119.  
  120.  
  121.  
  122.  
  123. // Creates the head of the bolt
  124. void RenderHead(void)
  125.     {
  126.     float x,y,angle;                // Calculated positions
  127.     float height = 25.0f;            // Thickness of the head
  128.     float diameter = 30.0f;            // Diameter of the head
  129.     float normal[3],corners[4][3];    // Storeage of vertices and normals
  130.     float step = (3.1415f/3.0f);    // step = 1/6th of a circle = hexagon
  131.  
  132.     
  133.     // Set material color for head of screw
  134.     glColor3f(0.0f, 0.0f, 0.7f);
  135.  
  136.     // clock-wise polygons face out, set for fans
  137.     glFrontFace(GL_CW);            
  138.  
  139.     // Begin a new triangle fan to cover the top
  140.     glBegin(GL_TRIANGLE_FAN);
  141.  
  142.         // All the normals for the top of the bolt point straight up
  143.         // the z axis.
  144.         glNormal3f(0.0f, 0.0f, 1.0f);
  145.  
  146.         // Center of fan is at the origin
  147.         glVertex3f(0.0f, 0.0f, 0.0f);
  148.  
  149.         // Divide the circle up into 6 sections and start dropping
  150.         // points to specify the fan
  151.         for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
  152.             {
  153.             // Calculate x and y position of the next vertex
  154.             x = diameter*(float)sin(angle);
  155.             y = diameter*(float)cos(angle);
  156.         
  157.             // Specify the next vertex for the triangle fan
  158.             glVertex3f(x, y, 0.0f);
  159.             }
  160.  
  161.         // Last vertex closes the fan
  162.         glVertex3f(0.0f, diameter, 0.0f);
  163.  
  164.     // Done drawing the fan that covers the bottom
  165.     glEnd();
  166.  
  167.     // Now draw the bottom of the bolt head. Now switch to
  168.     // clock-wise polygons faceing out.
  169.     glFrontFace(GL_CCW);            
  170.  
  171.     // Begin a new triangle fan to cover the bottom
  172.     glBegin(GL_TRIANGLE_FAN);
  173.  
  174.         // Normal for bottom points straight down the negative z axis
  175.         glNormal3f(0.0f, 0.0f, -1.0f);
  176.         
  177.         // Center of fan is at the origin
  178.         glVertex3f(0.0f, 0.0f, -height);
  179.  
  180.         // Divide the circle up into 6 sections and start dropping
  181.         // points to specify the fan
  182.         for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
  183.             {
  184.             // Calculate x and y position of the next vertex
  185.             x = diameter*(float)sin(angle);
  186.             y = diameter*(float)cos(angle);
  187.  
  188.             // Specify the next vertex for the triangle fan
  189.             glVertex3f(x, y, -height);
  190.             }
  191.  
  192.         // Last vertex, used to close the fan
  193.         glVertex3f(0.0f, diameter, -height);
  194.  
  195.     // Done drawing the fan that covers the bottom
  196.     glEnd();
  197.  
  198.  
  199.     // Build the sides out of triangles (two each). Each face
  200.     // will consist of two triangles arranged to form a 
  201.     // quadralateral
  202.     glBegin(GL_TRIANGLES);
  203.  
  204.         // Go around and draw the sides
  205.         for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
  206.             {
  207.             // Calculate x and y position of the next hex point
  208.             x = diameter*(float)sin(angle);
  209.             y = diameter*(float)cos(angle);
  210.         
  211.             // start at bottom of head
  212.             corners[0][0] = x;
  213.             corners[0][1] = y;
  214.             corners[0][2] = -height;
  215.  
  216.             // extrude to top of head
  217.             corners[1][0] = x;
  218.             corners[1][1] = y;
  219.             corners[1][2] = 0.0f;
  220.  
  221.             // Calculate the next hex point
  222.             x = diameter*(float)sin(angle+step);
  223.             y = diameter*(float)cos(angle+step);
  224.  
  225.             // Make sure we aren't done before proceeding
  226.             if(angle+step < 3.1415*2.0)
  227.                 {
  228.                 // If we are done, just close the fan at a 
  229.                 // known coordinate.
  230.                 corners[2][0] = x;
  231.                 corners[2][1] = y;
  232.                 corners[2][2] = 0.0f;
  233.  
  234.                 corners[3][0] = x;
  235.                 corners[3][1] = y;
  236.                 corners[3][2] = -height;
  237.                 }
  238.             else
  239.                 {
  240.                 // We aren't done, the points at the top and bottom
  241.                 // of the head.
  242.                 corners[2][0] = 0.0f;
  243.                 corners[2][1] = diameter;
  244.                 corners[2][2] = 0.0f;
  245.  
  246.                 corners[3][0] = 0.0f;
  247.                 corners[3][1] = diameter;
  248.                 corners[3][2] = -height;
  249.                 }
  250.  
  251.             // The normal vectors for the entire face will
  252.             // all point the same direction
  253.             calcNormal(corners, normal);
  254.             glNormal3fv(normal);
  255.         
  256.             // Specify each triangle seperately to lie next
  257.             // to each other.
  258.             glVertex3fv(corners[0]);
  259.             glVertex3fv(corners[1]);
  260.             glVertex3fv(corners[2]);
  261.         
  262.             glVertex3fv(corners[0]);
  263.             glVertex3fv(corners[2]);
  264.             glVertex3fv(corners[3]);
  265.             }
  266.  
  267.     glEnd();
  268.     }
  269.  
  270.  
  271.  
  272. // Creates the shaft of the bolt as a cylinder with one end
  273. // closed.
  274. void RenderShaft(void)
  275.     {
  276.     float x,y,angle;            // Used to calculate cylinder wall
  277.     float height = 75.0f;        // Height of the cylinder
  278.     float diameter = 20.0f;        // Diameter of the cylinder
  279.     float normal[3],corners[4][3];    // Storeage for vertices calculations
  280.     float step = (3.1415f/50.0f);    // Approximate the cylinder wall with
  281.                                     // 100 flat segments.
  282.  
  283.     
  284.     // Set material color for head of screw
  285.     glColor3f(0.0f, 0.0f, 0.7f);
  286.  
  287.     // counter clock-wise polygons face out (the default for triangles)
  288.     glFrontFace(GL_CCW);            
  289.  
  290.  
  291.     // First assemble the wall as 100 quadrilaterals formed by
  292.     // placing adjoining triangles together
  293.     glBegin(GL_TRIANGLES);
  294.  
  295.     // Go around and draw the sides
  296.     for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
  297.         {
  298.         // Calculate x and y position of the next vertex
  299.         x = diameter*(float)sin(angle);
  300.         y = diameter*(float)cos(angle);
  301.     
  302.         // Get the coordinate for this point and extrude the 
  303.         // length of the cylinder.
  304.         corners[0][0] = x;
  305.         corners[0][1] = y;
  306.         corners[0][2] = -height;
  307.  
  308.         corners[1][0] = x;
  309.         corners[1][1] = y;
  310.         corners[1][2] = 0.0f;
  311.  
  312.         // Get the next point and do the same
  313.         x = diameter*(float)sin(angle+step);
  314.         y = diameter*(float)cos(angle+step);
  315.  
  316.         // If finished, use know starting point to close the surface
  317.         if(angle+step < 3.1415*2.0) // Not Finished
  318.             {
  319.             corners[2][0] = x;
  320.             corners[2][1] = y;
  321.             corners[2][2] = 0.0f;
  322.  
  323.             corners[3][0] = x;
  324.             corners[3][1] = y;
  325.             corners[3][2] = -height;
  326.             }
  327.         else
  328.             {
  329.             // Finished, use the staring point
  330.             corners[2][0] = 0.0f;
  331.             corners[2][1] = diameter;
  332.             corners[2][2] = 0.0f;
  333.  
  334.             corners[3][0] = 0.0f;
  335.             corners[3][1] = diameter;
  336.             corners[3][2] = -height;
  337.             }
  338.  
  339.         // Instead of using real normal to actual flat section
  340.         // Use what the normal would be if the surface was really
  341.         // curved. Since the cylinder goes up the Z axis, the normal 
  342.         // points from the Z axis out directly through each vertex. 
  343.         // Therefore we can use the vertex as the normal, as long as
  344.         // we reduce it to unit length first.
  345.         
  346.         // First Triangle ////////////////////////////////////////
  347.         // Fill the normal vector with the coordinate points
  348.         normal[0] = corners[0][0];
  349.         normal[1] = corners[0][1];
  350.         normal[2] = corners[0][2];
  351.         
  352.         // Reduce to length of one and specify for this point
  353.         ReduceToUnit(normal);
  354.         glNormal3fv(normal);
  355.         glVertex3fv(corners[0]);
  356.  
  357.         // Get vertex, caluclate unit normal and go
  358.         normal[0] = corners[1][0];
  359.         normal[1] = corners[1][1];
  360.         normal[2] = corners[1][2];
  361.         ReduceToUnit(normal);
  362.         glNormal3fv(normal);
  363.         glVertex3fv(corners[1]);
  364.  
  365.         // Get vertex, caluclate unit normal and go
  366.         normal[0] = corners[2][0];
  367.         normal[1] = corners[2][1];
  368.         normal[2] = corners[2][2];
  369.         ReduceToUnit(normal);
  370.         glNormal3fv(normal);
  371.         glVertex3fv(corners[2]);
  372.  
  373.  
  374.         // Second Triangle ////////////////////////////////////////
  375.  
  376.         // Get vertex, caluclate unit normal and go
  377.         normal[0] = corners[2][0];
  378.         normal[1] = corners[2][1];
  379.         normal[2] = corners[2][2];
  380.         ReduceToUnit(normal);
  381.         glNormal3fv(normal);
  382.         glVertex3fv(corners[2]);
  383.  
  384.         // Get vertex, caluclate unit normal and go
  385.         normal[0] = corners[3][0];
  386.         normal[1] = corners[3][1];
  387.         normal[2] = corners[3][2];
  388.         ReduceToUnit(normal);
  389.         glNormal3fv(normal);
  390.         glVertex3fv(corners[3]);
  391.  
  392.         // Get vertex, caluclate unit normal and go
  393.         normal[0] = corners[0][0];
  394.         normal[1] = corners[0][1];
  395.         normal[2] = corners[0][2];
  396.         ReduceToUnit(normal);
  397.         glNormal3fv(normal);
  398.         glVertex3fv(corners[0]);
  399.         }
  400.  
  401.     glEnd();    // Done with cylinder sides
  402.  
  403.     // Begin a new triangle fan to cover the bottom
  404.     glBegin(GL_TRIANGLE_FAN);
  405.  
  406.     // Normal points down the Z axis
  407.     glNormal3f(0.0f, 0.0f, -1.0f);
  408.     
  409.     // Center of fan is at the origin
  410.     glVertex3f(0.0f, 0.0f, -height);
  411.     
  412.     // Spin around matching step size of cylinder wall
  413.     for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
  414.         {
  415.         // Calculate x and y position of the next vertex
  416.         x = diameter*(float)sin(angle);
  417.         y = diameter*(float)cos(angle);
  418.  
  419.         // Specify the next vertex for the triangle fan
  420.         glVertex3f(x, y, -height);
  421.         }
  422.  
  423.     // Close the fan
  424.     glVertex3f(0.0f, diameter, -height);
  425.     glEnd();
  426.     }
  427.  
  428.  
  429. // Creates the head of the bolt
  430. void RenderThread(void)
  431.     {
  432.     float x,y,z,angle;                // Calculate coordinates and step angle
  433.     float height = 75.0f;            // Height of the threading
  434.     float diameter = 20.0f;            // Diameter of the threading
  435.     float normal[3],corners[4][3];    // Storeage for calculate normal and corners
  436.     float step = (3.1415f/32.0f);    // one revolution
  437.     float revolutions = 7.0f;        // How many time around the shaft
  438.     float threadWidth = 2.0f;        // How wide is the thread
  439.     float threadThick = 3.0f;        // How thick is the thread
  440.     float zstep = .125f;            // How much does the thread move up
  441.                                     // the Z axis each time a new segment
  442.                                     // is drawn.
  443.  
  444.     // 360 degrees in radians
  445.     #define PI2 (2.0f*3.1415f)
  446.  
  447.     // Set material color for head of screw
  448.     glColor3f(0.0f, 0.0f, 0.4f);    
  449.         
  450.  
  451.     z = -height+2;    // Starting spot almost to the end
  452.  
  453.     // Go around and draw the sides until finished spinning up
  454.     for(angle = 0.0f; angle < PI2*revolutions; angle += step)
  455.         {
  456.         // Calculate x and y position of the next vertex
  457.         x = diameter*(float)sin(angle);
  458.         y = diameter*(float)cos(angle);
  459.     
  460.         // Store the next vertex next to the shaft
  461.         corners[0][0] = x;
  462.         corners[0][1] = y;
  463.         corners[0][2] = z;
  464.  
  465.         // Calculate the position away from the shaft
  466.         x = (diameter+threadWidth)*(float)sin(angle);
  467.         y = (diameter+threadWidth)*(float)cos(angle);
  468.  
  469.         corners[1][0] = x;
  470.         corners[1][1] = y;
  471.         corners[1][2] = z;
  472.  
  473.         // Calculate the next position away from the shaft
  474.         x = (diameter+threadWidth)*(float)sin(angle+step);
  475.         y = (diameter+threadWidth)*(float)cos(angle+step);
  476.  
  477.         corners[2][0] = x;
  478.         corners[2][1] = y;
  479.         corners[2][2] = z + zstep;
  480.  
  481.         // Calculate the next position along the shaft
  482.         x = (diameter)*(float)sin(angle+step);
  483.         y = (diameter)*(float)cos(angle+step);
  484.  
  485.         corners[3][0] = x;
  486.         corners[3][1] = y;
  487.         corners[3][2] = z+ zstep;
  488.     
  489.  
  490.         // We'll be using triangels, so make 
  491.         // counter clock-wise polygons face out
  492.         glFrontFace(GL_CCW);        
  493.         glBegin(GL_TRIANGLES);    // Start the top section of thread
  494.  
  495.             // Calculate the normal for this segment
  496.             calcNormal(corners, normal);
  497.             glNormal3fv(normal);
  498.  
  499.             // Draw two triangles to cover area
  500.             glVertex3fv(corners[0]);
  501.             glVertex3fv(corners[1]);
  502.             glVertex3fv(corners[2]);
  503.  
  504.             glVertex3fv(corners[2]);
  505.             glVertex3fv(corners[3]);
  506.             glVertex3fv(corners[0]);
  507.  
  508.         glEnd();
  509.  
  510.  
  511.         // Move the edge along the shaft slightly up the z axis
  512.         // to represent the bottom of the thread
  513.         corners[0][2] += threadThick;
  514.         corners[3][2] += threadThick;
  515.  
  516.         // Recalculate the normal since points have changed, this
  517.         // time it points in the opposite direction, so reverse it
  518.         calcNormal(corners, normal);
  519.         normal[0] = -normal[0];
  520.         normal[1] = -normal[1];
  521.         normal[2] = -normal[2];
  522.                 
  523.         // Switch to clock-wise facing out for underside of the
  524.         // thread.
  525.         glFrontFace(GL_CW);
  526.  
  527.         // Draw the two triangles
  528.         glBegin(GL_TRIANGLES);
  529.             glNormal3fv(normal);
  530.  
  531.             glVertex3fv(corners[0]);
  532.             glVertex3fv(corners[1]);
  533.             glVertex3fv(corners[2]);
  534.  
  535.             glVertex3fv(corners[2]);
  536.             glVertex3fv(corners[3]);
  537.             glVertex3fv(corners[0]);
  538.  
  539.         glEnd();
  540.  
  541.         // Creep up the Z axis
  542.         z += zstep;
  543.         }
  544.     }
  545.  
  546.  
  547.  
  548.  
  549. // This function does any needed initialization on the rendering
  550. // context.  Here it sets up and initializes the lighting for
  551. // the scene.
  552. void SetupRC()
  553.     {
  554.     // Light values and coordinates
  555.     GLfloat  ambientLight[] = {0.4f, 0.4f, 0.4f, 1.0f };
  556.     GLfloat  diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f };
  557.     GLfloat  specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
  558.     GLfloat     lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
  559.     GLfloat  specref[] =  { 0.6f, 0.6f, 0.6f, 1.0f };
  560.  
  561.  
  562.     glEnable(GL_DEPTH_TEST);    // Hidden surface removal
  563.     glEnable(GL_CULL_FACE);        // Do not calculate inside of solid object
  564.     
  565.     // Enable lighting
  566.     glEnable(GL_LIGHTING);
  567.  
  568.     // Setup light 0
  569.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
  570.     glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
  571.     glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
  572.     glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
  573.  
  574.     // Position and turn on the light
  575.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  576.     glEnable(GL_LIGHT0);
  577.  
  578.     // Enable color tracking
  579.     glEnable(GL_COLOR_MATERIAL);
  580.     
  581.     // Set Material properties to follow glColor values
  582.     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  583.  
  584.     // All materials hereafter have full specular reflectivity
  585.     // with a moderate shine
  586.     glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
  587.     glMateriali(GL_FRONT,GL_SHININESS,64);
  588.  
  589.     // Black background
  590.     glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
  591.  
  592.     // Create display list
  593.     glNewList(BOLT_HEAD,GL_COMPILE);
  594.         RenderHead();
  595.     glEndList();
  596.  
  597.     glNewList(BOLT_SHAFT,GL_COMPILE);
  598.         RenderShaft();
  599.     glEndList();
  600.  
  601.     glNewList(BOLT_THREAD,GL_COMPILE);
  602.         RenderThread();
  603.     glEndList();
  604.     }
  605.  
  606.  
  607.  
  608. // Called to draw the entire bolt
  609. void RenderScene(void)
  610.     {
  611.     // Clear the window with current clearing color
  612.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  613.  
  614.     // Save the matrix state and do the rotations
  615.     glMatrixMode(GL_MODELVIEW);
  616.  
  617.     // Rotate and translate, then render the bolt head
  618.     glPushMatrix();
  619.         glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  620.         glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  621.         glTranslatef(0.0f, 0.0f, 60.0f);
  622.         RenderHead();
  623.     glPopMatrix();
  624.  
  625.     // Save matrix state, rotate, translate and draw the
  626.     // shaft and thread together
  627.     glPushMatrix();
  628.     glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  629.     glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  630.     glTranslatef(0.0f, 0.0f, 40.0f);
  631.  
  632.     // Call two lists
  633.     glCallList(BOLT_SHAFT);
  634.     glCallList(BOLT_THREAD);
  635.  
  636.     glPopMatrix();
  637.  
  638.     // Flush drawing commands
  639.     glFlush();
  640.     }
  641.  
  642.  
  643. // Select the pixel format for a given device context
  644. void SetDCPixelFormat(HDC hDC)
  645.     {
  646.     int nPixelFormat;
  647.  
  648.     static PIXELFORMATDESCRIPTOR pfd = {
  649.         sizeof(PIXELFORMATDESCRIPTOR),  // Size of this structure
  650.         1,                                                              // Version of this structure    
  651.         PFD_DRAW_TO_WINDOW |                    // Draw to Window (not to bitmap)
  652.         PFD_SUPPORT_OPENGL |                    // Support OpenGL calls in window
  653.         PFD_DOUBLEBUFFER,                       // Double buffered
  654.         PFD_TYPE_RGBA,                          // RGBA Color mode
  655.         24,                                     // Want 24bit color 
  656.         0,0,0,0,0,0,                            // Not used to select mode
  657.         0,0,                                    // Not used to select mode
  658.         0,0,0,0,0,                              // Not used to select mode
  659.         32,                                     // Size of depth buffer
  660.         0,                                      // Not used to select mode
  661.         0,                                      // Not used to select mode
  662.         PFD_MAIN_PLANE,                         // Draw in main plane
  663.         0,                                      // Not used to select mode
  664.         0,0,0 };                                // Not used to select mode
  665.  
  666.     // Choose a pixel format that best matches that described in pfd
  667.     nPixelFormat = ChoosePixelFormat(hDC, &pfd);
  668.  
  669.     // Set the pixel format for the device context
  670.     SetPixelFormat(hDC, nPixelFormat, &pfd);
  671.     }
  672.  
  673.  
  674.  
  675. // If necessary, creates a 3-3-2 palette for the device context listed.
  676. HPALETTE GetOpenGLPalette(HDC hDC)
  677.     {
  678.     HPALETTE hRetPal = NULL;    // Handle to palette to be created
  679.     PIXELFORMATDESCRIPTOR pfd;    // Pixel Format Descriptor
  680.     LOGPALETTE *pPal;            // Pointer to memory for logical palette
  681.     int nPixelFormat;            // Pixel format index
  682.     int nColors;                // Number of entries in palette
  683.     int i;                        // Counting variable
  684.     BYTE RedRange,GreenRange,BlueRange;
  685.                                 // Range for each color entry (7,7,and 3)
  686.  
  687.  
  688.     // Get the pixel format index and retrieve the pixel format description
  689.     nPixelFormat = GetPixelFormat(hDC);
  690.     DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
  691.  
  692.     // Does this pixel format require a palette?  If not, do not create a
  693.     // palette and just return NULL
  694.     if(!(pfd.dwFlags & PFD_NEED_PALETTE))
  695.         return NULL;
  696.  
  697.     // Number of entries in palette.  8 bits yeilds 256 entries
  698.     nColors = 1 << pfd.cColorBits;    
  699.  
  700.     // Allocate space for a logical palette structure plus all the palette entries
  701.     pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));
  702.  
  703.     // Fill in palette header 
  704.     pPal->palVersion = 0x300;        // Windows 3.0
  705.     pPal->palNumEntries = nColors; // table size
  706.  
  707.     // Build mask of all 1's.  This creates a number represented by having
  708.     // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
  709.     // pfd.cBlueBits.  
  710.     RedRange = (1 << pfd.cRedBits) -1;
  711.     GreenRange = (1 << pfd.cGreenBits) - 1;
  712.     BlueRange = (1 << pfd.cBlueBits) -1;
  713.  
  714.     // Loop through all the palette entries
  715.     for(i = 0; i < nColors; i++)
  716.         {
  717.         // Fill in the 8-bit equivalents for each component
  718.         pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
  719.         pPal->palPalEntry[i].peRed = (unsigned char)(
  720.             (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);
  721.  
  722.         pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
  723.         pPal->palPalEntry[i].peGreen = (unsigned char)(
  724.             (double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
  725.  
  726.         pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
  727.         pPal->palPalEntry[i].peBlue = (unsigned char)(
  728.             (double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
  729.  
  730.         pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
  731.         }
  732.         
  733.  
  734.     // Create the palette
  735.     hRetPal = CreatePalette(pPal);
  736.  
  737.     // Go ahead and select and realize the palette for this device context
  738.     SelectPalette(hDC,hRetPal,FALSE);
  739.     RealizePalette(hDC);
  740.  
  741.     // Free the memory used for the logical palette structure
  742.     free(pPal);
  743.  
  744.     // Return the handle to the new palette
  745.     return hRetPal;
  746.     }
  747.  
  748.  
  749. // Entry point of all Windows programs
  750. int APIENTRY WinMain(   HINSTANCE       hInst,
  751.                         HINSTANCE       hPrevInstance,
  752.                         LPSTR           lpCmdLine,
  753.                         int                     nCmdShow)
  754.     {
  755.     MSG                     msg;            // Windows message structure
  756.     WNDCLASS        wc;                     // Windows class structure
  757.     HWND            hWnd;           // Storeage for window handle
  758.  
  759.     hInstance = hInst;
  760.  
  761.     // Register Window style
  762.     wc.style                        = CS_HREDRAW | CS_VREDRAW;
  763.     wc.lpfnWndProc          = (WNDPROC) WndProc;
  764.     wc.cbClsExtra           = 0;
  765.     wc.cbWndExtra           = 0;
  766.     wc.hInstance            = hInstance;
  767.     wc.hIcon                        = NULL;
  768.     wc.hCursor                      = LoadCursor(NULL, IDC_ARROW);
  769.     
  770.     // No need for background brush for OpenGL window
  771.     wc.hbrBackground        = NULL;         
  772.     
  773.     wc.lpszMenuName         = MAKEINTRESOURCE(IDR_MENU);
  774.     wc.lpszClassName        = lpszAppName;
  775.  
  776.     // Register the window class
  777.     if(RegisterClass(&wc) == 0)
  778.         return FALSE;
  779.  
  780.  
  781.     // Create the main application window
  782.     hWnd = CreateWindow(
  783.                 lpszAppName,
  784.                 lpszAppName,
  785.                 
  786.                 // OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
  787.                 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  788.     
  789.                 // Window position and size
  790.                 50, 50,
  791.                 400, 400,
  792.                 NULL,
  793.                 NULL,
  794.                 hInstance,
  795.                 NULL);
  796.  
  797.     // If window was not created, quit
  798.     if(hWnd == NULL)
  799.         return FALSE;
  800.  
  801.  
  802.     // Display the window
  803.     ShowWindow(hWnd,SW_SHOW);
  804.     UpdateWindow(hWnd);
  805.  
  806.     // Process application messages until the application closes
  807.     while( GetMessage(&msg, NULL, 0, 0))
  808.         {
  809.         TranslateMessage(&msg);
  810.         DispatchMessage(&msg);
  811.         }
  812.  
  813.     return msg.wParam;
  814.     }
  815.  
  816.  
  817.  
  818.  
  819. // Window procedure, handles all messages for this program
  820. LRESULT CALLBACK WndProc(       HWND    hWnd,
  821.                             UINT    message,
  822.                             WPARAM  wParam,
  823.                             LPARAM  lParam)
  824.     {
  825.     static HGLRC hRC;               // Permenant Rendering context
  826.     static HDC hDC;                 // Private GDI Device context
  827.  
  828.     switch (message)
  829.         {
  830.         // Window creation, setup for OpenGL
  831.         case WM_CREATE:
  832.             // Store the device context
  833.             hDC = GetDC(hWnd);              
  834.  
  835.             // Select the pixel format
  836.             SetDCPixelFormat(hDC);          
  837.  
  838.             hPalette = GetOpenGLPalette(hDC);
  839.  
  840.             // Create the rendering context and make it current
  841.             hRC = wglCreateContext(hDC);
  842.             wglMakeCurrent(hDC, hRC);
  843.             SetupRC();
  844.  
  845.             break;
  846.  
  847.         // Window is being destroyed, cleanup
  848.         case WM_DESTROY:
  849.             // Deselect the current rendering context and delete it
  850.             wglMakeCurrent(hDC,NULL);
  851.             wglDeleteContext(hRC);
  852.  
  853.             if(hPalette != NULL)
  854.                 DeleteObject(hPalette);
  855.  
  856.             // Tell the application to terminate after the window
  857.             // is gone.
  858.             PostQuitMessage(0);
  859.             break;
  860.  
  861.         // Window is resized.
  862.         case WM_SIZE:
  863.             // Call our function which modifies the clipping
  864.             // volume and viewport
  865.             ChangeSize(LOWORD(lParam), HIWORD(lParam));
  866.             break;
  867.  
  868.  
  869.         // The painting function.  This message sent by Windows 
  870.         // whenever the screen needs updating.
  871.         case WM_PAINT:
  872.             {
  873.             // Call OpenGL drawing code
  874.             RenderScene();
  875.  
  876.             SwapBuffers(hDC);
  877.  
  878.             // Validate the newly painted client area
  879.             ValidateRect(hWnd,NULL);
  880.             }
  881.             break;
  882.  
  883.         // Windows is telling the application that it may modify
  884.         // the system palette.  This message in essance asks the 
  885.         // application for a new palette.
  886.         case WM_QUERYNEWPALETTE:
  887.             // If the palette was created.
  888.             if(hPalette)
  889.                 {
  890.                 int nRet;
  891.  
  892.                 // Selects the palette into the current device context
  893.                 SelectPalette(hDC, hPalette, FALSE);
  894.  
  895.                 // Map entries from the currently selected palette to
  896.                 // the system palette.  The return value is the number 
  897.                 // of palette entries modified.
  898.                 nRet = RealizePalette(hDC);
  899.  
  900.                 // Repaint, forces remap of palette in current window
  901.                 InvalidateRect(hWnd,NULL,FALSE);
  902.  
  903.                 return nRet;
  904.                 }
  905.             break;
  906.  
  907.     
  908.         // This window may set the palette, even though it is not the 
  909.         // currently active window.
  910.         case WM_PALETTECHANGED:
  911.             // Don't do anything if the palette does not exist, or if
  912.             // this is the window that changed the palette.
  913.             if((hPalette != NULL) && ((HWND)wParam != hWnd))
  914.                 {
  915.                 // Select the palette into the device context
  916.                 SelectPalette(hDC,hPalette,FALSE);
  917.  
  918.                 // Map entries to system palette
  919.                 RealizePalette(hDC);
  920.                 
  921.                 // Remap the current colors to the newly realized palette
  922.                 UpdateColors(hDC);
  923.                 return 0;
  924.                 }
  925.             break;
  926.  
  927.         // Key press, check for arrow keys to do cube rotation.
  928.         case WM_KEYDOWN:
  929.             {
  930.             if(wParam == VK_UP)
  931.                 xRot-= 5.0f;
  932.  
  933.             if(wParam == VK_DOWN)
  934.                 xRot += 5.0f;
  935.  
  936.             if(wParam == VK_LEFT)
  937.                 yRot -= 5.0f;
  938.  
  939.             if(wParam == VK_RIGHT)
  940.                 yRot += 5.0f;
  941.  
  942.             xRot = (float)((const int)xRot % 360);
  943.             yRot = (float)((const int)yRot % 360);
  944.  
  945.             InvalidateRect(hWnd,NULL,FALSE);
  946.             }
  947.             break;
  948.  
  949.         // A menu command
  950.         case WM_COMMAND:
  951.             {
  952.             switch(LOWORD(wParam))
  953.                 {
  954.                 // Exit the program
  955.                 case ID_FILE_EXIT:
  956.                     DestroyWindow(hWnd);
  957.                     break;
  958.  
  959.                 // Display the about box
  960.                 case ID_HELP_ABOUT:
  961.                     DialogBox (hInstance,
  962.                         MAKEINTRESOURCE(IDD_DIALOG_ABOUT),
  963.                         hWnd,
  964.                         AboutDlgProc);
  965.                     break;
  966.                 }
  967.             }
  968.             break;
  969.  
  970.  
  971.     default:   // Passes it on if unproccessed
  972.         return (DefWindowProc(hWnd, message, wParam, lParam));
  973.  
  974.     }
  975.  
  976.     return (0L);
  977.     }
  978.  
  979.  
  980.  
  981.  
  982. // Dialog procedure.
  983. BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam)
  984.     {
  985.     
  986.     switch (message)
  987.     {
  988.         // Initialize the dialog box
  989.         case WM_INITDIALOG:
  990.             {
  991.             int i;
  992.             GLenum glError;
  993.  
  994.             // glGetString demo
  995.             SetDlgItemText(hDlg,IDC_OPENGL_VENDOR,glGetString(GL_VENDOR));
  996.             SetDlgItemText(hDlg,IDC_OPENGL_RENDERER,glGetString(GL_RENDERER));
  997.             SetDlgItemText(hDlg,IDC_OPENGL_VERSION,glGetString(GL_VERSION));
  998.             SetDlgItemText(hDlg,IDC_OPENGL_EXTENSIONS,glGetString(GL_EXTENSIONS));
  999.  
  1000.             // gluGetString demo
  1001.             SetDlgItemText(hDlg,IDC_GLU_VERSION,gluGetString(GLU_VERSION));
  1002.             SetDlgItemText(hDlg,IDC_GLU_EXTENSIONS,gluGetString(GLU_EXTENSIONS));
  1003.  
  1004.  
  1005.             // Display any recent error messages
  1006.             i = 0;
  1007.             do {
  1008.                 glError = glGetError();
  1009.                 SetDlgItemText(hDlg,IDC_ERROR1+i,gluErrorString(glError));
  1010.                 i++;
  1011.                 }
  1012.             while(i < 6 && glError != GL_NO_ERROR);
  1013.  
  1014.  
  1015.             return (TRUE);
  1016.             }
  1017.             break;
  1018.  
  1019.         // Process command messages
  1020.         case WM_COMMAND:      
  1021.             {
  1022.             // Validate and Make the changes
  1023.             if(LOWORD(wParam) == IDOK)
  1024.                 EndDialog(hDlg,TRUE);
  1025.             }
  1026.             break;
  1027.  
  1028.         // Closed from sysbox
  1029.         case WM_CLOSE:
  1030.             EndDialog(hDlg,TRUE);
  1031.             break;
  1032.         }
  1033.  
  1034.     return FALSE;
  1035.     }
  1036.