home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / GLUT / progs / contrib / steam.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  14.6 KB  |  620 lines

  1. /**
  2.  
  3.   Description: Interactive 3D graphics, Assignment #1
  4.                Miniature Steam Engine Simulation.
  5.   Author:      Troy Robinette
  6.   Date:        29/9/95
  7.   Email:       troyr@yallara.cs.rmit.edu.au
  8.   Notes:       - Transparence doesn't quite work. The color of the
  9.                  underlying object doesn't show through. 
  10.            - Also only the front side of the transparent objects are
  11.          transparent.
  12.  
  13. **/
  14.  
  15. #include <stdio.h>
  16. #include <GL/glut.h>
  17. #include <math.h>
  18.  
  19. #define TRUE  1
  20. #define FALSE 0
  21.  
  22. /* Dimensions of texture image. */
  23. #define IMAGE_WIDTH  64
  24. #define IMAGE_HEIGHT 64
  25.  
  26. /* Step to be taken for each rotation. */
  27. #define ANGLE_STEP 10
  28.  
  29. /* Magic numbers for relationship b/w cylinder head and crankshaft. */
  30. #define MAGNITUDE  120
  31. #define PHASE      270.112
  32. #define FREQ_DIV   58
  33. #define ARC_LENGHT 2.7
  34. #define ARC_RADIUS 0.15
  35.  
  36. /* Rotation angles */
  37. GLdouble view_h = 270, view_v = 0, head_angle = 0;
  38. GLint crank_angle = 0;
  39.  
  40. /* Crank rotation step. */
  41. GLdouble crank_step = 5;
  42.  
  43. /* Toggles */
  44. GLshort shaded = TRUE, anim = FALSE;
  45. GLshort texture = FALSE, transparent = FALSE;
  46. GLshort light1 = TRUE, light2 = FALSE;
  47.  
  48. /* Storage for the angle look up table and the texture map */
  49. GLdouble head_look_up_table[361];
  50. GLubyte image[IMAGE_WIDTH][IMAGE_HEIGHT][3];
  51.  
  52. /* Indentifiers for each Display list */
  53. GLint list_piston_shaded = 1;
  54. GLint list_piston_texture = 2;
  55. GLint list_flywheel_shaded = 4;
  56. GLint list_flywheel_texture = 8;
  57.  
  58. /* Variable used in the creaton of glu objects */
  59. GLUquadricObj *obj;
  60.  
  61. /* Draws a box by scaling a glut cube of size 1. Also checks the shaded 
  62.    toggle to see which rendering style to use. NB Texture doesn't work
  63.    correctly due to the cube being scaled. */
  64. void 
  65. myBox(GLdouble x, GLdouble y, GLdouble z)
  66. {
  67.   glPushMatrix();
  68.     glScalef(x, y, z);
  69.     if (shaded)
  70.       glutSolidCube(1);
  71.     else
  72.       glutWireCube(1);
  73.   glPopMatrix();
  74. }
  75.  
  76. /* Draws a cylinder using glu function, drawing flat disc's at each end,
  77.    to give the appearence of it being solid. */
  78. void 
  79. myCylinder(GLUquadricObj * object, GLdouble outerRadius,
  80.   GLdouble innerRadius, GLdouble lenght)
  81. {
  82.   glPushMatrix();
  83.     gluCylinder(object, outerRadius, outerRadius, lenght, 20, 1);
  84.     glPushMatrix();
  85.       glRotatef(180, 0.0, 1.0, 0.0);
  86.       gluDisk(object, innerRadius, outerRadius, 20, 1);
  87.     glPopMatrix();
  88.  
  89.     glTranslatef(0.0, 0.0, lenght);
  90.     gluDisk(object, innerRadius, outerRadius, 20, 1);
  91.   glPopMatrix();
  92. }
  93.  
  94. /* Draws a piston.  */
  95. void 
  96. draw_piston(void)
  97. {
  98.   glPushMatrix();
  99.     glColor4f(0.3, 0.6, 0.9, 1.0);
  100.  
  101.     glPushMatrix();
  102.       glRotatef(90, 0.0, 1.0, 0.0);
  103.       glTranslatef(0.0, 0.0, -0.07);
  104.       myCylinder(obj, 0.125, 0.06, 0.12);
  105.     glPopMatrix();
  106.  
  107.     glRotatef(-90, 1.0, 0.0, 0.0);
  108.     glTranslatef(0.0, 0.0, 0.05);
  109.     myCylinder(obj, 0.06, 0.0, 0.6);
  110.     glTranslatef(0.0, 0.0, 0.6);
  111.     myCylinder(obj, 0.2, 0.0, 0.5);
  112.   glPopMatrix();
  113. }
  114.  
  115. /* Draws the engine pole and the pivot pole for the cylinder head. */
  116. void 
  117. draw_engine_pole(void)
  118. {
  119.   glPushMatrix();
  120.     glColor4f(0.9, 0.9, 0.9, 1.0);
  121.     myBox(0.5, 3.0, 0.5);
  122.  
  123.     glColor3f(0.5, 0.1, 0.5);
  124.     glRotatef(90, 0.0, 1.0, 0.0);
  125.     glTranslatef(0.0, 0.9, -0.4);
  126.     myCylinder(obj, 0.1, 0.0, 2);
  127.   glPopMatrix();
  128. }
  129.  
  130. /* Draws the cylinder head at the appropreate angle, doing the necesary 
  131.    translations for the rotation. */
  132. void 
  133. draw_cylinder_head(void)
  134. {
  135.   glPushMatrix();
  136.     glColor4f(0.5, 1.0, 0.5, 0.1);
  137.     glRotatef(90, 1.0, 0.0, 0.0);
  138.     glTranslatef(0, 0.0, 0.4);
  139.     glRotatef(head_angle, 1, 0, 0);
  140.     glTranslatef(0, 0.0, -0.4);
  141.     myCylinder(obj, 0.23, 0.21, 1.6);
  142.     glRotatef(180, 1.0, 0.0, 0.0);
  143.     gluDisk(obj, 0, 0.23, 20, 1);
  144.   glPopMatrix();
  145. }
  146.  
  147. /* Draws the flywheel.  */
  148. void 
  149. draw_flywheel(void)
  150. {
  151.   glPushMatrix();
  152.     glColor4f(0.5, 0.5, 1.0, 1.0);
  153.     glRotatef(90, 0.0, 1.0, 0.0);
  154.     myCylinder(obj, 0.625, 0.08, 0.5);
  155.   glPopMatrix();
  156. }
  157.  
  158. /* Draws the crank bell, and the pivot pin for the piston. Also calls the
  159.    appropreate display list of a piston doing the nesacary rotations before
  160.    hand.  */
  161. void 
  162. draw_crankbell(void)
  163. {
  164.   glPushMatrix();
  165.     glColor4f(1.0, 0.5, 0.5, 1.0);
  166.     glRotatef(90, 0.0, 1.0, 0.0);
  167.     myCylinder(obj, 0.3, 0.08, 0.12);
  168.  
  169.     glColor4f(0.5, 0.1, 0.5, 1.0);
  170.     glTranslatef(0.0, 0.2, 0.0);
  171.     myCylinder(obj, 0.06, 0.0, 0.34);
  172.  
  173.     glTranslatef(0.0, 0.0, 0.22);
  174.     glRotatef(90, 0.0, 1.0, 0.0);
  175.     glRotatef(crank_angle - head_angle, 1.0, 0.0, 0.0);
  176.     if (shaded) {
  177.       if (texture)
  178.         glCallList(list_piston_texture);
  179.       else
  180.         glCallList(list_piston_shaded);
  181.     } else
  182.       draw_piston();
  183.   glPopMatrix();
  184. }
  185.  
  186. /* Draws the complete crank. Piston also gets drawn through the crank bell
  187.    function. */
  188. void 
  189. draw_crank(void)
  190. {
  191.   glPushMatrix();
  192.     glRotatef(crank_angle, 1.0, 0.0, 0.0);
  193.  
  194.     glPushMatrix();
  195.       glRotatef(90, 0.0, 1.0, 0.0);
  196.       glTranslatef(0.0, 0.0, -1.0);
  197.       myCylinder(obj, 0.08, 0.0, 1.4);
  198.     glPopMatrix();
  199.  
  200.     glPushMatrix();
  201.       glTranslatef(0.28, 0.0, 0.0);
  202.       draw_crankbell();
  203.     glPopMatrix();
  204.  
  205.     glPushMatrix();
  206.       glTranslatef(-0.77, 0.0, 0.0);
  207.       if (shaded) {
  208.         if (texture)
  209.           glCallList(list_flywheel_texture);
  210.         else
  211.           glCallList(list_flywheel_shaded);
  212.       } else
  213.         draw_flywheel();
  214.     glPopMatrix();
  215.   glPopMatrix();
  216. }
  217.  
  218. /* Main display routine. Clears the drawing buffer and if transparency is
  219.    set, displays the model twice, 1st time accepting those fragments with 
  220.    a ALPHA value of 1 only, then with DEPTH_BUFFER writing disabled for 
  221.    those with other values. */
  222. void 
  223. display(void)
  224. {
  225.   int pass;
  226.  
  227.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  228.  
  229.   glPushMatrix();
  230.     if (transparent) {
  231.       glEnable(GL_ALPHA_TEST);
  232.       pass = 2;
  233.     } else {
  234.       glDisable(GL_ALPHA_TEST);
  235.       pass = 0;
  236.     }
  237.  
  238.     /* Rotate the whole model */
  239.     glRotatef(view_h, 0, 1, 0);
  240.     glRotatef(view_v, 1, 0, 0);
  241.  
  242.     do {
  243.       if (pass == 2) {
  244.         glAlphaFunc(GL_EQUAL, 1);
  245.         glDepthMask(GL_TRUE);
  246.         pass--;
  247.       } else if (pass != 0) {
  248.         glAlphaFunc(GL_NOTEQUAL, 1);
  249.         glDepthMask(GL_FALSE);
  250.         pass--;
  251.       }
  252.       draw_engine_pole();
  253.  
  254.       glPushMatrix();
  255.         glTranslatef(0.5, 1.4, 0.0);
  256.         draw_cylinder_head();
  257.       glPopMatrix();
  258.  
  259.       glPushMatrix();
  260.         glTranslatef(0.0, -0.8, 0.0);
  261.         draw_crank();
  262.       glPopMatrix();
  263.     } while (pass > 0);
  264.     glDepthMask(GL_TRUE);
  265.     glutSwapBuffers();
  266.   glPopMatrix();
  267. }
  268.  
  269. /* Called when the window is idle. When called increments the crank angle
  270.    by ANGLE_STEP, updates the head angle and notifies the system that
  271.    the screen needs to be updated. */
  272. void 
  273. animation(void)
  274. {
  275.   if ((crank_angle += crank_step) >= 360)
  276.     crank_angle = 0;
  277.   head_angle = head_look_up_table[crank_angle];
  278.   glutPostRedisplay();
  279. }
  280.  
  281. /* Called when a key is pressed. Checks if it reconises the key and if so
  282.    acts on it, updateing the screen. */
  283. void 
  284. keyboard(unsigned char key, int x, int y)
  285. {
  286.   switch (key) {
  287.   case 's':
  288.     if (shaded == FALSE) {
  289.       shaded = TRUE;
  290.       glShadeModel(GL_SMOOTH);
  291.       glEnable(GL_LIGHTING);
  292.       glEnable(GL_DEPTH_TEST);
  293.       glEnable(GL_COLOR_MATERIAL);
  294.       gluQuadricNormals(obj, GLU_SMOOTH);
  295.       gluQuadricDrawStyle(obj, GLU_FILL);
  296.     } else {
  297.       shaded = FALSE;
  298.       glShadeModel(GL_FLAT);
  299.       glDisable(GL_LIGHTING);
  300.       glDisable(GL_DEPTH_TEST);
  301.       glDisable(GL_COLOR_MATERIAL);
  302.       gluQuadricNormals(obj, GLU_NONE);
  303.       gluQuadricDrawStyle(obj, GLU_LINE);
  304.       gluQuadricTexture(obj, GL_FALSE);
  305.     }
  306.     if (texture && !shaded);
  307.     else
  308.       break;
  309.   case 't':
  310.     if (texture == FALSE) {
  311.       texture = TRUE;
  312.       glEnable(GL_TEXTURE_2D);
  313.       gluQuadricTexture(obj, GL_TRUE);
  314.     } else {
  315.       texture = FALSE;
  316.       glDisable(GL_TEXTURE_2D);
  317.       gluQuadricTexture(obj, GL_FALSE);
  318.     }
  319.     break;
  320.   case 'o':
  321.     if (transparent == FALSE) {
  322.       transparent = TRUE;
  323.     } else {
  324.       transparent = FALSE;
  325.     }
  326.     break;
  327.  
  328.   case 'a':
  329.     if ((crank_angle += crank_step) >= 360)
  330.       crank_angle = 0;
  331.     head_angle = head_look_up_table[crank_angle];
  332.     break;
  333.   case 'z':
  334.     if ((crank_angle -= crank_step) <= 0)
  335.       crank_angle = 360;
  336.     head_angle = head_look_up_table[crank_angle];
  337.     break;
  338.   case '0':
  339.     if (light1) {
  340.       glDisable(GL_LIGHT0);
  341.       light1 = FALSE;
  342.     } else {
  343.       glEnable(GL_LIGHT0);
  344.       light1 = TRUE;
  345.     }
  346.     break;
  347.   case '1':
  348.     if (light2) {
  349.       glDisable(GL_LIGHT1);
  350.       light2 = FALSE;
  351.     } else {
  352.       glEnable(GL_LIGHT1);
  353.       light2 = TRUE;
  354.     }
  355.     break;
  356.   case '4':
  357.     if ((view_h -= ANGLE_STEP) <= 0)
  358.       view_h = 360;
  359.     break;
  360.   case '6':
  361.     if ((view_h += ANGLE_STEP) >= 360)
  362.       view_h = 0;
  363.     break;
  364.   case '8':
  365.     if ((view_v += ANGLE_STEP) >= 360)
  366.       view_v = 0;
  367.     break;
  368.   case '2':
  369.     if ((view_v -= ANGLE_STEP) <= 0)
  370.       view_v = 360;
  371.     break;
  372.   case ' ':
  373.     if (anim) {
  374.       glutIdleFunc(0);
  375.       anim = FALSE;
  376.     } else {
  377.       glutIdleFunc(animation);
  378.       anim = TRUE;
  379.     }
  380.     break;
  381.   case '+':
  382.     if ((++crank_step) > 45)
  383.       crank_step = 45;
  384.     break;
  385.   case '-':
  386.     if ((--crank_step) <= 0)
  387.       crank_step = 0;
  388.     break;
  389.   default:
  390.     return;
  391.   }
  392.   glutPostRedisplay();
  393. }
  394.  
  395. void
  396. special(int key, int x, int y)
  397. {
  398.   switch (key) {
  399.   case GLUT_KEY_LEFT:
  400.     if ((view_h -= ANGLE_STEP) <= 0)
  401.       view_h = 360;
  402.     break;
  403.   case GLUT_KEY_RIGHT:
  404.     if ((view_h += ANGLE_STEP) >= 360)
  405.       view_h = 0;
  406.     break;
  407.   case GLUT_KEY_UP:
  408.     if ((view_v += ANGLE_STEP) >= 360)
  409.       view_v = 0;
  410.     break;
  411.   case GLUT_KEY_DOWN:
  412.     if ((view_v -= ANGLE_STEP) <= 0)
  413.       view_v = 360;
  414.     break;
  415.   default:
  416.     return;
  417.   }
  418.   glutPostRedisplay();
  419. }
  420.  
  421. /* Called when a menu option has been selected. Translates the menu item
  422.    identifier into a keystroke, then call's the keyboard function. */
  423. void 
  424. menu(int val)
  425. {
  426.   unsigned char key;
  427.  
  428.   switch (val) {
  429.   case 1:
  430.     key = 's';
  431.     break;
  432.   case 2:
  433.     key = ' ';
  434.     break;
  435.   case 3:
  436.     key = 't';
  437.     break;
  438.   case 4:
  439.     key = 'o';
  440.     break;
  441.   case 5:
  442.     key = '0';
  443.     break;
  444.   case 6:
  445.     key = '1';
  446.     break;
  447.   case 7:
  448.     key = '+';
  449.     break;
  450.   case 8:
  451.     key = '-';
  452.     break;
  453.   default:
  454.     return;
  455.   }
  456.   keyboard(key, 0, 0);
  457. }
  458.  
  459. /* Initialises the menu of toggles. */
  460. void 
  461. create_menu(void)
  462. {
  463.   glutCreateMenu(menu);
  464.   glutAttachMenu(GLUT_LEFT_BUTTON);
  465.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  466.   glutAddMenuEntry("Shaded", 1);
  467.   glutAddMenuEntry("Animation", 2);
  468.   glutAddMenuEntry("Texture", 3);
  469.   glutAddMenuEntry("Transparency", 4);
  470.   glutAddMenuEntry("Right Light (0)", 5);
  471.   glutAddMenuEntry("Left Light (1)", 6);
  472.   glutAddMenuEntry("Speed UP", 7);
  473.   glutAddMenuEntry("Slow Down", 8);
  474. }
  475.  
  476. /* Makes a simple check pattern image. (Copied from the redbook example
  477.    "checker.c".) */
  478. void
  479. make_image(void)
  480. {
  481.   int i, j, c;
  482.  
  483.   for (i = 0; i < IMAGE_WIDTH; i++) {
  484.     for (j = 0; j < IMAGE_HEIGHT; j++) {
  485.       c = ((((i & 0x8) == 0) ^ ((j & 0x8)) == 0)) * 255;
  486.       image[i][j][0] = (GLubyte) c;
  487.       image[i][j][1] = (GLubyte) c;
  488.       image[i][j][2] = (GLubyte) c;
  489.     }
  490.   }
  491. }
  492.  
  493. /* Makes the head look up table for all possible crank angles. */
  494. void 
  495. make_table(void)
  496. {
  497.   GLint i;
  498.   GLdouble k;
  499.  
  500.   for (i = 0, k = 0.0; i < 360; i++, k++) {
  501.     head_look_up_table[i] =
  502.       MAGNITUDE * atan(
  503.       (ARC_RADIUS * sin(PHASE - k / FREQ_DIV)) /
  504.       ((ARC_LENGHT - ARC_RADIUS * cos(PHASE - k / FREQ_DIV))));
  505.   }
  506. }
  507.  
  508. /* Initialises texturing, lighting, display lists, and everything else 
  509.    associated with the model. */
  510. void 
  511. myinit(void)
  512. {
  513.   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
  514.   GLfloat mat_shininess[] = {50.0};
  515.   GLfloat light_position1[] = {1.0, 1.0, 1.0, 0.0};
  516.   GLfloat light_position2[] = {-1.0, 1.0, 1.0, 0.0};
  517.  
  518.   glClearColor(0.0, 0.0, 0.0, 0.0);
  519.  
  520.   obj = gluNewQuadric();
  521.   make_table();
  522.   make_image();
  523.  
  524.   /* Set up Texturing */
  525.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  526.   glTexImage2D(GL_TEXTURE_2D, 0, 3, IMAGE_WIDTH,
  527.     IMAGE_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
  528.     image);
  529.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  530.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  531.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  532.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  533.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  534.  
  535.   /* Set up Lighting */
  536.   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  537.   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  538.   glLightfv(GL_LIGHT0, GL_POSITION, light_position1);
  539.   glLightfv(GL_LIGHT1, GL_POSITION, light_position2);
  540.  
  541.   /* Initial render mode is with full shading and LIGHT 0
  542.      enabled. */
  543.   glEnable(GL_LIGHTING);
  544.   glEnable(GL_LIGHT0);
  545.   glDepthFunc(GL_LEQUAL);
  546.   glEnable(GL_DEPTH_TEST);
  547.   glDisable(GL_ALPHA_TEST);
  548.  
  549.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  550.   glEnable(GL_COLOR_MATERIAL);
  551.   glShadeModel(GL_SMOOTH);
  552.  
  553.   /* Initialise display lists */
  554.   glNewList(list_piston_shaded, GL_COMPILE);
  555.     draw_piston();
  556.   glEndList();
  557.   glNewList(list_flywheel_shaded, GL_COMPILE);
  558.     draw_flywheel();
  559.   glEndList();
  560.  
  561.   gluQuadricTexture(obj, GL_TRUE);
  562.   glNewList(list_piston_texture, GL_COMPILE);
  563.     draw_piston();
  564.   glEndList();
  565.   glNewList(list_flywheel_texture, GL_COMPILE);
  566.     draw_flywheel();
  567.   glEndList();
  568.   gluQuadricTexture(obj, GL_FALSE);
  569. }
  570.  
  571. /* Called when the model's window has been reshaped.  */
  572. void 
  573. myReshape(int w, int h)
  574. {
  575.   glViewport(0, 0, w, h);
  576.   glMatrixMode(GL_PROJECTION);
  577.   glLoadIdentity();
  578.   gluPerspective(65.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0);
  579.   glMatrixMode(GL_MODELVIEW);
  580.   glLoadIdentity();
  581.   glTranslatef(0.0, 0.0, -5.0);  /* viewing transform  */
  582.   glScalef(1.5, 1.5, 1.5);
  583. }
  584.  
  585. /* Main program. An interactive model of a miniture steam engine.
  586.    Sets system in Double Buffered mode and initialises all the call-back
  587.    functions. */
  588. int 
  589. main(int argc, char **argv)
  590. {
  591.   puts("Miniature Steam Engine                    Troy Robinette\n");
  592.  
  593.   puts("Keypad Arrow keys (with NUM_LOCK on) rotates object.");
  594.   puts("Rotate crank: 'a' = anti-clock wise 'z' = clock wise");
  595.   puts("Crank Speed : '+' = Speed up by 1   '-' = Slow Down by 1");
  596.   puts("Toggle      : 's' = Shading         't' = Texture");
  597.   puts("            : ' ' = Animation       'o' = Transparency");
  598.   puts("            : '0' = Right Light     '1' = Left Light");
  599.   puts(" Alternatively a pop up menu with all toggles is attached");
  600.   puts("   to the left mouse button.\n");
  601.  
  602.   glutInitWindowSize(400, 400);
  603.   glutInit(&argc, argv);
  604.  
  605.   /* Transperancy won't work properly without GLUT_ALPHA */
  606.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);
  607.   glutCreateWindow("Miniature Steam Engine by Troy Robinette");
  608.  
  609.   glutDisplayFunc(display);
  610.   glutKeyboardFunc(keyboard);
  611.   glutSpecialFunc(special);
  612.   create_menu();
  613.  
  614.   myinit();
  615.  
  616.   glutReshapeFunc(myReshape);
  617.   glutMainLoop();
  618.   return 0;             /* ANSI C requires main to return int. */
  619. }
  620.