hanoi2.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:10k
源码类别:

GIS编程

开发平台:

Visual C++

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