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 / hanoi2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  9.8 KB  |  446 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <getopt.h>
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/prctl.h>
  7. #include <unistd.h>
  8. #include <GL/glut.h>
  9.  
  10. #define MAX_DISKS 6
  11.  
  12. #define DISK_HEIGHT 0.2
  13. #define CYL_RADIUS 0.1
  14. #define CYL_HEIGHT 1.8
  15. #define OVER_CLICKS 120
  16. #define UP_CLICKS 120
  17.  
  18. enum {X=0, Y, Z};
  19. enum {DL_POLE=1, DL_FLOOR, DL_DISK};               /* disk must be last */
  20.  
  21. /* motion states */
  22. enum {ST_UP=1, ST_TO_1, ST_TO_2, ST_DOWN, ST_READNEXT, ST_IDLE};
  23.  
  24. int motion = 1;
  25. int spinning = 1;
  26. int click = 0;
  27. int delay = 0;
  28. int direction;
  29. int state=ST_READNEXT;
  30. int c_pole;
  31. int old_pole;
  32. int c_disk;
  33. int engine_fd;
  34. int engine_pid;
  35.  
  36. float pole_offset[3][2] = { { 0, -0.575 },
  37.                 { 1.15, 0.575 },
  38.                             { -1.15, 0.575 } };
  39. float disk_offset[MAX_DISKS][3] = {{ 0, -0.575, 0},
  40.                    { 0, -0.575, 0},   
  41.                    { 0, -0.575, 0},   
  42.                    { 0, -0.575, 0},   
  43.                    { 0, -0.575, 0},   
  44.                    { 0, -0.575, 0}};
  45. float disk_incr[3] = { 0, 0, 0 };
  46.  
  47. int num_disks;
  48. struct {
  49.   int num_disks;
  50.   int disks[MAX_DISKS];
  51. } disks_on_poles[3];
  52.  
  53. /*
  54.  * create display list for disk of outside radius orad
  55.  */
  56. void
  57. diskdlist(int dlist, float orad)
  58. {
  59.     GLUquadricObj *obj;
  60.  
  61.     obj = gluNewQuadric();
  62.     if (obj == 0) {
  63.     perror("can't alloc quadric");
  64.     exit(1);
  65.     }
  66.     glNewList(dlist, GL_COMPILE);
  67.     glPushMatrix();
  68.       glColor4ub(205, 67, 100, 200);
  69.       gluQuadricDrawStyle(obj, GLU_FILL);
  70.  
  71.       gluQuadricOrientation(obj, GLU_OUTSIDE);
  72.       gluCylinder(obj, orad, orad, DISK_HEIGHT, 20, 4);
  73.  
  74.       gluQuadricOrientation(obj, GLU_INSIDE);
  75.       gluCylinder(obj, CYL_RADIUS, CYL_RADIUS, DISK_HEIGHT, 20, 4);
  76.  
  77.       gluQuadricOrientation(obj, GLU_INSIDE);
  78.       gluDisk(obj, CYL_RADIUS, orad, 20, 4);
  79.  
  80.       gluQuadricOrientation(obj, GLU_OUTSIDE);
  81.       glPushMatrix();
  82.         glTranslatef(0.0, 0.0, DISK_HEIGHT);
  83.         gluDisk(obj, CYL_RADIUS, orad, 20, 4);
  84.       glPopMatrix();
  85.     glPopMatrix();
  86.     glEndList();
  87. }
  88.  
  89. /*
  90.  * create display list for pole
  91.  */
  92. void
  93. poledlist(int dlist)
  94. {
  95.     GLUquadricObj *obj;
  96.  
  97.     obj = gluNewQuadric();
  98.     if (obj == 0) {
  99.     perror("can't alloc quadric");
  100.     exit(1);
  101.     }
  102.  
  103.     glNewList(dlist, GL_COMPILE);
  104.     glPushMatrix();
  105.       glColor3ub(67, 205, 128);
  106.       gluQuadricDrawStyle(obj, GLU_FILL);
  107.       gluQuadricOrientation(obj, GLU_OUTSIDE);
  108.  
  109.       gluCylinder(obj, CYL_RADIUS, CYL_RADIUS, CYL_HEIGHT, 12, 3);
  110.  
  111.       gluQuadricOrientation(obj, GLU_INSIDE);
  112.       gluDisk(obj, 0.0, CYL_RADIUS, 12, 3);
  113.  
  114.       gluQuadricOrientation(obj, GLU_OUTSIDE);
  115.       glPushMatrix();
  116.         glTranslatef(0.0, 0.0, CYL_HEIGHT);
  117.         gluDisk(obj, 0.0, CYL_RADIUS, 12, 3);
  118.       glPopMatrix();
  119.     glPopMatrix();
  120.     glEndList();
  121.  
  122. }
  123.  
  124. /*
  125.  * create display list for floor
  126.  */
  127. void
  128. floordlist(int dlist)
  129. {
  130.     glNewList(dlist, GL_COMPILE);
  131.     glPushMatrix();
  132.       glColor4ub(90, 100, 230,100);
  133.  
  134.       /* top/bottom */
  135.       glBegin(GL_TRIANGLE_STRIP);
  136.       glNormal3f(0.0, 0.0, 1.0);
  137.       glVertex3f(-2.0, -2.0, 0);
  138.       glVertex3f(2.0, -2.0, 0);
  139.       glVertex3f(-2.0, 2.0, 0);
  140.       glVertex3f(2.0, 2.0, 0);
  141.       glEnd();
  142.       glPushMatrix();
  143.         glTranslatef(0, 0, -0.2);
  144.         glBegin(GL_TRIANGLE_STRIP);
  145.         glNormal3f(0.0, 0.0, -1.0);
  146.         glVertex3f(2.0, -2.0, 0);
  147.         glVertex3f(-2.0, -2.0, 0);
  148.         glVertex3f(2.0, 2.0, 0);
  149.         glVertex3f(-2.0, 2.0, 0);
  150.         glEnd();
  151.       glPopMatrix();
  152.  
  153.       /* edges */
  154.       glBegin(GL_TRIANGLE_STRIP);
  155.       glNormal3f(-1.0, 0.0, 0.0);
  156.       glVertex3f(-2.0, -2.0, -0.2);
  157.       glVertex3f(-2.0, -2.0, 0);
  158.       glVertex3f(-2.0, 2.0, -0.2);
  159.       glVertex3f(-2.0, 2.0, 0);
  160.       glNormal3f(0.0, 1.0, 0.0);
  161.       glVertex3f(2.0, 2.0, -0.2);
  162.       glVertex3f(2.0, 2.0, 0);
  163.       glNormal3f(1.0, 0.0, 0.0);
  164.       glVertex3f(2.0, -2.0, -0.2);
  165.       glVertex3f(2.0, -2.0, 0);
  166.       glNormal3f(0.0, -1.0, 0.0);
  167.       glVertex3f(-2.0, -2.0, -0.2);
  168.       glVertex3f(-2.0, -2.0, 0);
  169.       glEnd();
  170.     glPopMatrix();
  171.     glEndList();
  172. }
  173.  
  174. /*
  175.  * motion state machine -- idle loop
  176.  */
  177. void
  178. idle(void)
  179. {
  180.   static int over_clicks;
  181.   int rc;
  182.   char next_move[3];
  183.  
  184.   if (spinning)
  185.     click++;
  186.  
  187.   if (motion) {
  188.       switch(state) {
  189.     case ST_READNEXT:
  190.       /*
  191.        * read an instruction from the hanoi engine
  192.        */
  193.       rc = read(engine_fd, next_move, 3);
  194.       if (rc == 3 && next_move[0] == 'M') {
  195.           /* choose poles/disks to move */
  196.            old_pole = next_move[1];
  197.           c_pole = next_move[2];
  198.           c_disk = disks_on_poles[old_pole].disks[disks_on_poles[old_pole].num_disks - 1];
  199.           state = ST_UP;
  200.           disk_incr[Z] = CYL_HEIGHT / (float)UP_CLICKS;
  201.       }
  202.       else if (rc == 3 && next_move[0] == 'D') {
  203.           state = ST_IDLE;
  204.       }
  205.       else if (rc != 0) {
  206.           fprintf(stderr,"bad read; %d, [%d%d%d]\n",
  207.               rc, next_move[0], next_move[1], next_move[2]);
  208.           exit(1);
  209.       }
  210.       /* if rc == 0, do nothing this frame */
  211.       break;
  212.  
  213.     case ST_UP:
  214.       disk_offset[c_disk][Z] += disk_incr[Z];
  215.       if (disk_offset[c_disk][Z] >= (CYL_HEIGHT+0.1)) {
  216.           state = ST_TO_1;
  217.           over_clicks = OVER_CLICKS;
  218.           disk_incr[X] = (pole_offset[c_pole][X] 
  219.                   - pole_offset[old_pole][X]) / (float)(over_clicks-1);
  220.           disk_incr[Y] = (pole_offset[c_pole][Y] 
  221.                   - pole_offset[old_pole][Y]) / (float)(over_clicks-1);
  222.           disk_incr[Z] = 0.0;
  223.       }
  224.       break;
  225.  
  226.     case ST_DOWN:
  227.       disk_offset[c_disk][Z] -= disk_incr[Z];
  228.       if (disk_offset[c_disk][Z] <= (disks_on_poles[c_pole].num_disks*0.2+disk_incr[Z])) {
  229.           disk_offset[c_disk][Z] = disks_on_poles[c_pole].num_disks*0.2;
  230.           disks_on_poles[old_pole].num_disks --;
  231.           disks_on_poles[c_pole].disks[disks_on_poles[c_pole].num_disks ++] = c_disk;
  232.           state = ST_READNEXT;
  233.       }
  234.       break;
  235.  
  236.     case ST_TO_1:
  237.     case ST_TO_2:
  238.       disk_offset[c_disk][X] += disk_incr[X];
  239.       disk_offset[c_disk][Y] += disk_incr[Y];
  240.       over_clicks --;
  241.       if (over_clicks == 0) {
  242.           state = ST_DOWN;
  243.           disk_incr[X] = 0.0;
  244.           disk_incr[Y] = 0.0;
  245.           disk_incr[Z] = CYL_HEIGHT / (float)UP_CLICKS;
  246.           disk_offset[c_disk][X] = pole_offset[c_pole][X]; /* paranoia */
  247.           disk_offset[c_disk][Y] = pole_offset[c_pole][Y];
  248.       }
  249.       break;
  250.  
  251.     case ST_IDLE:
  252.       break;
  253.       }
  254.   }
  255.   glutPostRedisplay();
  256. }
  257.  
  258. void
  259. draw_scene(void)
  260. {
  261.   int i;
  262.   glPushMatrix();
  263.     glRotatef(click, 0, 0, 1);
  264.     glRotatef(click/5.0, 1, 0, 0);
  265.     for (i=0; i<3; i++) {
  266.       glPushMatrix();
  267.     glTranslatef(pole_offset[i][X], pole_offset[i][Y], 0);
  268.         glCallList(DL_POLE);
  269.       glPopMatrix();
  270.     }
  271.     for(i=0; i<num_disks; i++) {
  272.       glPushMatrix();
  273.     glTranslatef(disk_offset[i][X], disk_offset[i][Y], disk_offset[i][Z]);
  274.     glCallList(DL_DISK+i);
  275.       glPopMatrix();
  276.     }
  277. #ifndef TOOSLOW
  278.     glCallList(DL_FLOOR);
  279. #endif
  280.   glPopMatrix();
  281. }
  282.  
  283. void
  284. display(void)
  285. {
  286.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  287.   draw_scene();
  288.  
  289.   glutSwapBuffers();
  290. }
  291.  
  292. void
  293. decide_animation(void)
  294. {
  295.   if(motion || spinning) {
  296.     glutIdleFunc(idle);
  297.   } else {
  298.     glutIdleFunc(NULL);
  299.   }
  300. }
  301.  
  302. void
  303. visible(int state)
  304. {
  305.   if (state == GLUT_VISIBLE) {
  306.     decide_animation();
  307.   } else {
  308.     glutIdleFunc(NULL);
  309.   }
  310. }
  311.  
  312. void
  313. menu(int value)
  314. {
  315.   switch (value) {
  316.   case 2:
  317.     motion = 1 - motion;
  318.     decide_animation();
  319.     break;
  320.   case 3:
  321.     spinning = 1 - spinning;
  322.     decide_animation();
  323.     break;
  324.   case 666:
  325.     kill(engine_pid, SIGTERM);
  326.     exit(0);
  327.   }
  328. }
  329.  
  330. int
  331. main(int argc, char *argv[])
  332. {
  333.   int c;
  334.   int i;
  335.  
  336.   GLfloat mat_specular[] = { 0.7, 0.7, 0.7, 1.0 };
  337.   GLfloat mat_shininess[] = { 40.0 };
  338.   GLfloat light_position[] = { 4.5, 0.0, 4.5, 0.0 };
  339.  
  340.   glutInit(&argc, argv);
  341.  
  342.   num_disks = MAX_DISKS;
  343.   while((c = getopt(argc, argv, "n:s:m:")) != -1) {
  344.       switch (c) {
  345.     case 'n':
  346.       num_disks = atoi(optarg);
  347.       if (num_disks < 1 || num_disks > MAX_DISKS) {
  348.           num_disks = MAX_DISKS;
  349.       }
  350.       break;
  351.     case 's':
  352.       spinning = atoi(optarg) ? 1 : 0;
  353.       break;
  354.     case 'm':
  355.       motion = atoi(optarg) ? 1 : 0;
  356.       break;
  357.     default:
  358.       break;
  359.       }
  360.   }
  361.  
  362.   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
  363.   glutCreateWindow("Hanoi");
  364.   glutDisplayFunc(display);
  365.   glutVisibilityFunc(visible);
  366.   glMatrixMode(GL_PROJECTION);
  367.   gluPerspective(40.0, 1.0, 0.1, 10.0);
  368.   glMatrixMode(GL_MODELVIEW);
  369.   gluLookAt(0, 5.5, 3.5,
  370.     0, 0, 0,
  371.     0, 0, 1);
  372.   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  373. #ifndef TOOSLOW
  374.   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  375.   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  376.   glEnable(GL_COLOR_MATERIAL);
  377. #endif
  378. #ifndef TOOSLOW
  379.   glShadeModel(GL_SMOOTH);
  380. #endif
  381.   glEnable(GL_DEPTH_TEST);
  382.   glEnable(GL_CULL_FACE);
  383. #ifndef TOOSLOW
  384.   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  385.   glEnable(GL_LIGHTING);
  386.   glEnable(GL_LIGHT0);
  387. #endif
  388.   glDepthFunc(GL_LEQUAL);
  389.   glClearColor(0.3, 0.3, 0.3, 0.0);
  390. #ifndef TOOSLOW
  391.   glEnable(GL_BLEND);
  392.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  393. #endif
  394.  
  395.   glPolygonMode(GL_FRONT, GL_FILL);
  396.  
  397.   glutCreateMenu(menu);
  398.   glutAddMenuEntry("Toggle motion", 2);
  399.   glutAddMenuEntry("Toggle spinning", 3);
  400.   glutAddMenuEntry("Quit", 666);
  401.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  402. #if defined(GL_POLYGON_OFFSET_EXT)
  403.   if (glutExtensionSupported("GL_EXT_polygon_offset")) {
  404.     glPolygonOffsetEXT(0.5, 0.0);
  405.     glEnable(GL_POLYGON_OFFSET_EXT);
  406.   }
  407. #endif
  408.  
  409.   poledlist(DL_POLE);
  410.   floordlist(DL_FLOOR);
  411.   
  412.   disks_on_poles[0].num_disks = num_disks;
  413.   for (i=0; i<num_disks; i++) {
  414.       diskdlist(DL_DISK+i, 0.3 + i*0.1);
  415.       disks_on_poles[0].disks[num_disks-i-1] = i;
  416.       disk_offset[i][Z] = 0.2*(num_disks-i-1);
  417.   }
  418.  
  419.   /*
  420.    * start hanoi instruction engine
  421.    */
  422.   {
  423.       int engine_args[2];
  424.       extern void engine(int *);
  425.       int p[2];
  426.  
  427.       prctl(PR_SETEXITSIG, SIGTERM);
  428.       if (-1 == pipe(p)) {
  429.       perror("can't pipe");
  430.       exit(1);
  431.       }
  432.       engine_args[0] = num_disks;
  433.       engine_args[1] = p[1];
  434.       engine_fd = p[0];
  435.       engine_pid = sproc((void(*)(void *))engine, PR_SALL, (void *)engine_args);
  436.       if (engine_pid == -1) {
  437.       perror("can't sproc");
  438.       exit(1);
  439.       }
  440.   }
  441.  
  442.   glutMainLoop();
  443.   /*NOTREACHED*/
  444.   return 0;             /* ANSI C requires main to return int. */
  445. }
  446.