home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / book / Chap09 / Thread / Thread.c next >
Encoding:
C/C++ Source or Header  |  1999-08-19  |  8.1 KB  |  330 lines

  1. // Thread.c
  2. // OpenGL SuperBible, Chapter 9
  3. // Demonstrates rendering a single piece of a model (Bolt Threads)
  4. // Program by Richard S. Wright Jr.
  5.  
  6. #include <windows.h>
  7. #include <gl/gl.h>
  8. #include <gl/glu.h>
  9. #include <gl/glut.h>
  10. #include <math.h>
  11.  
  12.  
  13. // Define a constant for the value of PI
  14. #define GL_PI 3.1415f
  15.  
  16. // Rotation amounts
  17. static GLfloat xRot = 0.0f;
  18. static GLfloat yRot = 0.0f;
  19.  
  20.  
  21. // Reduces a normal vector specified as a set of three coordinates,
  22. // to a unit normal vector of length one.
  23. void ReduceToUnit(float vector[3])
  24.     {
  25.     float length;
  26.     
  27.     // Calculate the length of the vector        
  28.     length = (float)sqrt((vector[0]*vector[0]) + 
  29.                         (vector[1]*vector[1]) +
  30.                         (vector[2]*vector[2]));
  31.  
  32.     // Keep the program from blowing up by providing an exceptable
  33.     // value for vectors that may calculated too close to zero.
  34.     if(length == 0.0f)
  35.         length = 1.0f;
  36.  
  37.     // Dividing each element by the length will result in a
  38.     // unit normal vector.
  39.     vector[0] /= length;
  40.     vector[1] /= length;
  41.     vector[2] /= length;
  42.     }
  43.  
  44.  
  45. // Points p1, p2, & p3 specified in counter clock-wise order
  46. void calcNormal(float v[3][3], float out[3])
  47.     {
  48.     float v1[3],v2[3];
  49.     static const int x = 0;
  50.     static const int y = 1;
  51.     static const int z = 2;
  52.  
  53.     // Calculate two vectors from the three points
  54.     v1[x] = v[0][x] - v[1][x];
  55.     v1[y] = v[0][y] - v[1][y];
  56.     v1[z] = v[0][z] - v[1][z];
  57.  
  58.     v2[x] = v[1][x] - v[2][x];
  59.     v2[y] = v[1][y] - v[2][y];
  60.     v2[z] = v[1][z] - v[2][z];
  61.  
  62.     // Take the cross product of the two vectors to get
  63.     // the normal vector which will be stored in out
  64.     out[x] = v1[y]*v2[z] - v1[z]*v2[y];
  65.     out[y] = v1[z]*v2[x] - v1[x]*v2[z];
  66.     out[z] = v1[x]*v2[y] - v1[y]*v2[x];
  67.  
  68.     // Normalize the vector (shorten length to one)
  69.     ReduceToUnit(out);
  70.     }
  71.  
  72.  
  73. // Creates the thread that spirals along the body of the bolt
  74. void RenderThread(void)
  75.     {
  76.     float x,y,z,angle;                // Calculate coordinates and step angle
  77.     float height = 75.0f;            // Height of the threading
  78.     float diameter = 20.0f;            // Diameter of the threading
  79.     float normal[3],corners[4][3];    // Storeage for calculate normal and corners
  80.     float step = (3.1415f/32.0f);    // one revolution
  81.     float revolutions = 7.0f;        // How many time around the shaft
  82.     float threadWidth = 2.0f;        // How wide is the thread
  83.     float threadThick = 3.0f;        // How thick is the thread
  84.     float zstep = .125f;            // How much does the thread move up
  85.                                     // the Z axis each time a new segment
  86.                                     // is drawn.
  87.  
  88.     // 360 degrees in radians
  89.     #define PI2 (2.0f*3.1415f)
  90.  
  91.     // Set material color for head of screw
  92.     glColor3f(0.0f, 0.0f, 0.4f);    
  93.         
  94.  
  95.     z = -height/2.0f+2;    // Starting spot almost to the end
  96.  
  97.     // Go around and draw the sides until finished spinning up
  98.     for(angle = 0.0f; angle < PI2*revolutions; angle += step)
  99.         {
  100.         // Calculate x and y position of the next vertex
  101.         x = diameter*(float)sin(angle);
  102.         y = diameter*(float)cos(angle);
  103.     
  104.         // Store the next vertex next to the shaft
  105.         corners[0][0] = x;
  106.         corners[0][1] = y;
  107.         corners[0][2] = z;
  108.  
  109.         // Calculate the position away from the shaft
  110.         x = (diameter+threadWidth)*(float)sin(angle);
  111.         y = (diameter+threadWidth)*(float)cos(angle);
  112.  
  113.         corners[1][0] = x;
  114.         corners[1][1] = y;
  115.         corners[1][2] = z;
  116.  
  117.         // Calculate the next position away from the shaft
  118.         x = (diameter+threadWidth)*(float)sin(angle+step);
  119.         y = (diameter+threadWidth)*(float)cos(angle+step);
  120.  
  121.         corners[2][0] = x;
  122.         corners[2][1] = y;
  123.         corners[2][2] = z + zstep;
  124.  
  125.         // Calculate the next position along the shaft
  126.         x = (diameter)*(float)sin(angle+step);
  127.         y = (diameter)*(float)cos(angle+step);
  128.  
  129.         corners[3][0] = x;
  130.         corners[3][1] = y;
  131.         corners[3][2] = z+ zstep;
  132.     
  133.  
  134.         // We'll be using triangels, so make 
  135.         // counter clock-wise polygons face out
  136.         glFrontFace(GL_CCW);        
  137.         glBegin(GL_TRIANGLES);    // Start the top section of thread
  138.  
  139.             // Calculate the normal for this segment
  140.             calcNormal(corners, normal);
  141.             glNormal3fv(normal);
  142.  
  143.             // Draw two triangles to cover area
  144.             glVertex3fv(corners[0]);
  145.             glVertex3fv(corners[1]);
  146.             glVertex3fv(corners[2]);
  147.  
  148.             glVertex3fv(corners[2]);
  149.             glVertex3fv(corners[3]);
  150.             glVertex3fv(corners[0]);
  151.  
  152.         glEnd();
  153.  
  154.  
  155.         // Move the edge along the shaft slightly up the z axis
  156.         // to represent the bottom of the thread
  157.         corners[0][2] += threadThick;
  158.         corners[3][2] += threadThick;
  159.  
  160.         // Recalculate the normal since points have changed, this
  161.         // time it points in the opposite direction, so reverse it
  162.         calcNormal(corners, normal);
  163.         normal[0] = -normal[0];
  164.         normal[1] = -normal[1];
  165.         normal[2] = -normal[2];
  166.                 
  167.         // Switch to clock-wise facing out for underside of the
  168.         // thread.
  169.         glFrontFace(GL_CW);
  170.  
  171.         // Draw the two triangles
  172.         glBegin(GL_TRIANGLES);
  173.             glNormal3fv(normal);
  174.  
  175.             glVertex3fv(corners[0]);
  176.             glVertex3fv(corners[1]);
  177.             glVertex3fv(corners[2]);
  178.  
  179.             glVertex3fv(corners[2]);
  180.             glVertex3fv(corners[3]);
  181.             glVertex3fv(corners[0]);
  182.  
  183.         glEnd();
  184.  
  185.         // Creep up the Z axis
  186.         z += zstep;
  187.         }
  188.     }
  189.  
  190.  
  191. // Called to draw scene
  192. void RenderScene(void)
  193.     {
  194.     // Clear the window with current clearing color
  195.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  196.  
  197.     // Save the matrix state
  198.     glMatrixMode(GL_MODELVIEW);
  199.     glPushMatrix();
  200.     
  201.     // Rotate about x and y axes
  202.     glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  203.     glRotatef(yRot, 0.0f, 0.0f, 1.0f);
  204.  
  205.     // Render just the Thread of the nut
  206.     RenderThread();
  207.  
  208.     glPopMatrix();
  209.  
  210.     // Swap buffers
  211.     glutSwapBuffers();
  212.     }
  213.  
  214.  
  215. // This function does any needed initialization on the rendering
  216. // context. 
  217. void SetupRC()
  218.     {
  219.     // Light values and coordinates
  220.     GLfloat  ambientLight[] = {0.4f, 0.4f, 0.4f, 1.0f };
  221.     GLfloat  diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f };
  222.     GLfloat  specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
  223.     GLfloat     lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
  224.     GLfloat  specref[] =  { 0.6f, 0.6f, 0.6f, 1.0f };
  225.  
  226.  
  227.     glEnable(GL_DEPTH_TEST);    // Hidden surface removal
  228.     glEnable(GL_CULL_FACE);        // Do not calculate inside of solid object
  229.     glFrontFace(GL_CCW);
  230.     
  231.     // Enable lighting
  232.     glEnable(GL_LIGHTING);
  233.  
  234.     // Setup light 0
  235.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
  236.     glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
  237.     glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
  238.     glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
  239.  
  240.     // Position and turn on the light
  241.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  242.     glEnable(GL_LIGHT0);
  243.  
  244.     // Enable color tracking
  245.     glEnable(GL_COLOR_MATERIAL);
  246.     
  247.     // Set Material properties to follow glColor values
  248.     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  249.  
  250.     // All materials hereafter have full specular reflectivity
  251.     // with a moderate shine
  252.     glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
  253.     glMateriali(GL_FRONT,GL_SHININESS,64);
  254.  
  255.     // Black background
  256.     glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
  257.     }
  258.  
  259. ///////////////////////////////////////////////////////////////////////////////
  260. // Process arrow keys
  261. void SpecialKeys(int key, int x, int y)
  262.     {
  263.     if(key == GLUT_KEY_UP)
  264.         xRot-= 5.0f;
  265.  
  266.     if(key == GLUT_KEY_DOWN)
  267.         xRot += 5.0f;
  268.  
  269.     if(key == GLUT_KEY_LEFT)
  270.         yRot -= 5.0f;
  271.  
  272.     if(key == GLUT_KEY_RIGHT)
  273.         yRot += 5.0f;
  274.  
  275.     if(key > 356.0f)
  276.         xRot = 0.0f;
  277.  
  278.     if(key < -1.0f)
  279.         xRot = 355.0f;
  280.  
  281.     if(key > 356.0f)
  282.         yRot = 0.0f;
  283.  
  284.     if(key < -1.0f)
  285.         yRot = 355.0f;
  286.  
  287.     // Refresh the Window
  288.     glutPostRedisplay();
  289.     }
  290.  
  291.  
  292. void ChangeSize(int w, int h)
  293.     {
  294.     GLfloat nRange = 100.0f;
  295.  
  296.     // Prevent a divide by zero
  297.     if(h == 0)
  298.         h = 1;
  299.  
  300.     // Set Viewport to window dimensions
  301.     glViewport(0, 0, w, h);
  302.  
  303.     // Reset coordinate system
  304.     glMatrixMode(GL_PROJECTION);
  305.     glLoadIdentity();
  306.  
  307.     // Establish clipping volume (left, right, bottom, top, near, far)
  308.     if (w <= h) 
  309.         glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange*2.0f, nRange*2.0f);
  310.     else 
  311.         glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange*2.0f, nRange*2.0f);
  312.  
  313.     glMatrixMode(GL_MODELVIEW);
  314.     glLoadIdentity();
  315.     }
  316.  
  317. int main(int argc, char* argv[])
  318.     {
  319.     glutInit(&argc, argv);
  320.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  321.     glutCreateWindow("Bolt Thread");
  322.     glutReshapeFunc(ChangeSize);
  323.     glutSpecialFunc(SpecialKeys);
  324.     glutDisplayFunc(RenderScene);
  325.     SetupRC();
  326.     glutMainLoop();
  327.  
  328.     return 0;
  329.     }
  330.