home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible / OpenGL_Superbible_Waite_Group_Press_1996.iso / book / chapt10 / wow / newbolt.c next >
C/C++ Source or Header  |  1996-07-06  |  39KB  |  1,033 lines

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