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

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