STEAM.C
上传用户:tengyuc
上传日期:2007-08-14
资源大小:722k
文件大小:15k
源码类别:

OpenGL

开发平台:

Visual C++

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