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

GIS编程

开发平台:

Visual C++

  1. #include <assert.h>
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <GL/glut.h>
  6. GLUquadricObj *cone, *base, *qsphere;
  7. /* Some <math.h> files do not define M_PI... */
  8. #ifndef M_PI
  9. #define M_PI 3.14159265358979323846
  10. #endif
  11. #ifndef __sgi
  12. #define trunc(x) ((double)((int)(x)))
  13. #endif
  14. int draw_passes = 8;
  15. int headsUp = 0;
  16. typedef struct {
  17.   GLfloat verts[4][3];
  18.   GLfloat scale[3];
  19.   GLfloat trans[3];
  20. } Mirror;
  21. Mirror mirrors[] = {
  22.   /* mirror on the left wall */
  23.   {{{-1., -.75, -.75}, {-1., .75, -.75}, {-1., .75, .75}, {-1, -.75, .75}},
  24.      {-1, 1, 1}, {2, 0, 0}},
  25.   /* mirror on right wall */
  26.   {{{1., -.75, .75}, {1., .75, .75}, {1., .75, -.75}, {1., -.75, -.75}},
  27.      {-1, 1, 1}, {-2, 0, 0}},
  28. };
  29. int nMirrors = 2;
  30. void init(void)
  31. {
  32.   static GLfloat lightpos[] = {.5, .75, 1.5, 1};
  33.   glEnable(GL_DEPTH_TEST); 
  34.   glEnable(GL_LIGHTING);
  35.   glEnable(GL_LIGHT0);
  36.   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  37.   glEnable(GL_CULL_FACE);
  38.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  39.   cone = gluNewQuadric();
  40.   qsphere = gluNewQuadric();
  41. }
  42. void make_viewpoint(void)
  43. {
  44.   if (headsUp) {
  45.     float width = (1 + 2*(draw_passes/nMirrors)) * 1.25;
  46.     float height = (width / tan((30./360.) * (2.*M_PI))) + 1;
  47.     glMatrixMode(GL_PROJECTION);
  48.     glLoadIdentity();
  49.     gluPerspective(60, 1, height - 3, height + 3);
  50.     gluLookAt(0, height, 0,
  51.       0, 0, 0, 
  52.       0, 0, 1);
  53.   } else {
  54.     glMatrixMode(GL_PROJECTION);
  55.     glLoadIdentity();
  56.     gluPerspective(60, 1, .01, 4 + 2*(draw_passes / nMirrors));
  57.     gluLookAt(-2, 0, .75, 
  58.       0, 0, 0, 
  59.       0, 1, 0);
  60.   }
  61.     
  62.   glMatrixMode(GL_MODELVIEW);
  63.   glLoadIdentity();
  64. }
  65. void reshape(GLsizei w, GLsizei h) 
  66. {
  67.   glViewport(0, 0, w, h);
  68.   make_viewpoint();
  69. }
  70. void draw_room(void)
  71. {
  72.   /* material for the walls, floor, ceiling */
  73.   static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f};
  74.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
  75.   glBegin(GL_QUADS);
  76.   
  77.   /* floor */
  78.   glNormal3f(0, 1, 0);
  79.   glVertex3f(-1, -1, 1);
  80.   glVertex3f(1, -1, 1);
  81.   glVertex3f(1, -1, -1);
  82.   glVertex3f(-1, -1, -1);
  83.   /* ceiling */
  84.   glNormal3f(0, -1, 0);
  85.   glVertex3f(-1, 1, -1);
  86.   glVertex3f(1, 1, -1);
  87.   glVertex3f(1, 1, 1);
  88.   glVertex3f(-1, 1, 1);  
  89.   /* left wall */
  90.   glNormal3f(1, 0, 0);
  91.   glVertex3f(-1, -1, -1);
  92.   glVertex3f(-1, 1, -1);
  93.   glVertex3f(-1, 1, 1);
  94.   glVertex3f(-1, -1, 1);
  95.   /* right wall */
  96.   glNormal3f(-1, 0, 0);
  97.   glVertex3f(1, -1, 1);
  98.   glVertex3f(1, 1, 1);
  99.   glVertex3f(1, 1, -1);
  100.   glVertex3f(1, -1, -1);
  101.   /* far wall */
  102.   glNormal3f(0, 0, 1);
  103.   glVertex3f(-1, -1, -1);
  104.   glVertex3f(1, -1, -1);
  105.   glVertex3f(1, 1, -1);
  106.   glVertex3f(-1, 1, -1);
  107.   /* back wall */
  108.   glNormal3f(0, 0, -1);
  109.   glVertex3f(-1, 1, 1);
  110.   glVertex3f(1, 1, 1);
  111.   glVertex3f(1, -1, 1);
  112.   glVertex3f(-1, -1, 1);
  113.   glEnd();
  114. }
  115. void draw_cone(void)
  116. {
  117.   static GLfloat cone_mat[] = {0.f, .5f, 1.f, 1.f};
  118.   glPushMatrix();
  119.   glTranslatef(0, -1, 0);
  120.   glRotatef(-90, 1, 0, 0);
  121.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  122.   gluCylinder(cone, .3, 0, 1.25, 20, 1);
  123.   glPopMatrix();
  124. }
  125. void draw_sphere(GLdouble secs)
  126. {
  127.   static GLfloat sphere_mat[] = {1.f, .5f, 0.f, 1.f};
  128.   GLfloat angle;
  129.   /* one revolution every 10 seconds... */
  130.   secs = secs - 10.*trunc(secs / 10.);
  131.   angle = (secs/10.) * (360.);
  132.   glPushMatrix();
  133.   glTranslatef(0, -.3, 0);
  134.   glRotatef(angle, 0, 1, 0);
  135.   glTranslatef(.6, 0, 0);
  136.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
  137.   gluSphere(qsphere, .3, 20, 20);
  138.   glPopMatrix();
  139. }
  140. GLdouble get_secs(void)
  141. {
  142.   return glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  143. }
  144. void draw_mirror(Mirror *m)
  145. {
  146.   glBegin(GL_QUADS);
  147.   glVertex3fv(m->verts[0]);
  148.   glVertex3fv(m->verts[1]);
  149.   glVertex3fv(m->verts[2]);
  150.   glVertex3fv(m->verts[3]);
  151.   glEnd();
  152. }
  153. /* A note on matrix management:  it would be easier to use push and
  154.  * pop to save and restore the matrices, but the projection matrix stack
  155.  * is very shallow, so we just undo what we did.  In the extreme this
  156.  * could lead to mathematic error. */
  157. GLenum reflect_through_mirror(Mirror *m, GLenum cullFace)
  158. {
  159.   GLenum newCullFace = ((cullFace == GL_FRONT) ? GL_BACK : GL_FRONT);
  160.   glMatrixMode(GL_PROJECTION);
  161.   glScalef(m->scale[0], m->scale[1], m->scale[2]); 
  162.   glTranslatef(m->trans[0], m->trans[1], m->trans[2]); 
  163.   glMatrixMode(GL_MODELVIEW);
  164.   /* must flip the cull face since reflection reverses the orientation
  165.    * of the polygons */
  166.   glCullFace(newCullFace);
  167.   return newCullFace;
  168. }
  169. void undo_reflect_through_mirror(Mirror *m, GLenum cullFace)
  170. {
  171.   glMatrixMode(GL_PROJECTION);
  172.   glTranslatef(-m->trans[0], -m->trans[1], -m->trans[2]);
  173.   glScalef(1./m->scale[0], 1./m->scale[1], 1./m->scale[2]);
  174.   glMatrixMode(GL_MODELVIEW);
  175.   glCullFace(cullFace);
  176. }
  177. void draw_scene(GLdouble secs, int passes, GLenum cullFace, 
  178. GLuint stencilVal, GLuint mirror)
  179. {
  180.   GLenum newCullFace;
  181.   int passesPerMirror, passesPerMirrorRem;
  182.   unsigned int curMirror, drawMirrors;
  183.   int i;
  184.   /* one pass to draw the real scene */
  185.   passes--;
  186.   /* only draw in my designated locations */
  187.   glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff);
  188.   /* draw things which may obscure the mirrors first */
  189.   draw_sphere(secs);
  190.   draw_cone();
  191.   /* now draw the appropriate number of mirror reflections.  for
  192.    * best results, we perform a depth-first traversal by allocating
  193.    * a number of passes for each of the mirrors. */
  194.   if (mirror != 0xffffffff) {
  195.     passesPerMirror = passes / (nMirrors - 1);
  196.     passesPerMirrorRem = passes % (nMirrors - 1);
  197.     if (passes > nMirrors - 1) drawMirrors = nMirrors - 1;
  198.     else drawMirrors = passes;
  199.   } else {
  200.     /* mirror == -1 means that this is the initial scene (there was no 
  201.      * mirror) */
  202.     passesPerMirror = passes / nMirrors;
  203.     passesPerMirrorRem = passes % nMirrors;
  204.     if (passes > nMirrors) drawMirrors = nMirrors;
  205.     else drawMirrors = passes;
  206.   }
  207.   for (i = 0; drawMirrors > 0; i++) {
  208.     curMirror = i % nMirrors;
  209.     if (curMirror == mirror) continue;
  210.     drawMirrors--;
  211.     /* draw mirror into stencil buffer but not color or depth buffers */
  212.     glColorMask(0, 0, 0, 0);
  213.     glDepthMask(0);
  214.     glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 
  215.     draw_mirror(&mirrors[curMirror]);
  216.     glColorMask(1, 1, 1, 1);
  217.     glDepthMask(1);
  218.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  219.     /* draw reflected scene */
  220.     newCullFace = reflect_through_mirror(&mirrors[curMirror], cullFace);
  221.     if (passesPerMirrorRem) {
  222.       draw_scene(secs, passesPerMirror + 1, newCullFace, stencilVal + 1, 
  223.  curMirror);      
  224.       passesPerMirrorRem--;
  225.     } else {
  226.       draw_scene(secs, passesPerMirror, newCullFace, stencilVal + 1, 
  227.  curMirror);
  228.     }
  229.     undo_reflect_through_mirror(&mirrors[curMirror], cullFace);
  230.     /* back to our stencil value */
  231.     glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff);    
  232.   }
  233.   draw_room(); 
  234. }
  235. void draw(void)
  236. {
  237.   GLenum err;
  238.   GLfloat secs = get_secs();
  239.   
  240.   glDisable(GL_STENCIL_TEST);
  241.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  242.   
  243.   if (!headsUp) glEnable(GL_STENCIL_TEST);
  244.   draw_scene(secs, draw_passes, GL_BACK, 0, (unsigned)-1);
  245.   glDisable(GL_STENCIL_TEST);
  246.   if (headsUp) {
  247.     /* draw a red floor on the original scene */
  248.     glDisable(GL_LIGHTING);
  249.     glBegin(GL_QUADS);
  250.     glColor3f(1, 0, 0);
  251.     glVertex3f(-1, -.95, 1);
  252.     glVertex3f(1, -.95, 1);
  253.     glVertex3f(1, -.95, -1);
  254.     glVertex3f(-1, -.95, -1);    
  255.     glEnd();
  256.     glEnable(GL_LIGHTING);
  257.   }
  258.   err = glGetError();
  259.   if (err != GL_NO_ERROR) printf("Error:  %sn", gluErrorString(err));
  260.   
  261.   glutSwapBuffers(); 
  262. }
  263. /* ARGSUSED1 */
  264. void key(unsigned char key, int x, int y)
  265. {
  266.   switch(key) {
  267.   case '.':  case '>':  case '+':  case '=':
  268.     draw_passes++;
  269.     printf("Passes = %dn", draw_passes);
  270.     make_viewpoint();
  271.     break;
  272.   case ',':  case '<':  case '-':  case '_':
  273.     draw_passes--;
  274.     if (draw_passes < 1) draw_passes = 1;
  275.     printf("Passes = %dn", draw_passes);
  276.     make_viewpoint();
  277.     break;
  278.   case 'h':  case 'H':
  279.     /* heads up mode */
  280.     headsUp = (headsUp == 0);
  281.     make_viewpoint();
  282.     break;
  283.   case 27:
  284.     exit(0);
  285.   }
  286. }
  287. #define MIN_COLOR_BITS 4
  288. #define MIN_DEPTH_BITS 8
  289. main(int argc, char *argv[])
  290. {
  291.     glutInit(&argc, argv);
  292.     glutInitWindowSize(256, 256);
  293.     glutInitWindowPosition(0, 0);
  294.     if (argc > 1) {
  295.       glutInitDisplayString("samples stencil>=3 rgb depth");
  296.     } else { 
  297.       glutInitDisplayString("samples stencil>=3 rgb double depth");
  298.     }
  299.     glutCreateWindow(argv[0]);
  300.     glutDisplayFunc(draw);
  301.     glutIdleFunc(draw);
  302.     glutKeyboardFunc(key);
  303.     glutReshapeFunc(reshape);
  304.     init();
  305.     glutMainLoop();
  306.     return 0;
  307. }