multimirror.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:9k
- #include <assert.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <GL/glut.h>
- GLUquadricObj *cone, *base, *qsphere;
- /* Some <math.h> files do not define M_PI... */
- #ifndef M_PI
- #define M_PI 3.14159265358979323846
- #endif
- #ifndef __sgi
- #define trunc(x) ((double)((int)(x)))
- #endif
- int draw_passes = 8;
- int headsUp = 0;
- typedef struct {
- GLfloat verts[4][3];
- GLfloat scale[3];
- GLfloat trans[3];
- } Mirror;
- Mirror mirrors[] = {
- /* mirror on the left wall */
- {{{-1., -.75, -.75}, {-1., .75, -.75}, {-1., .75, .75}, {-1, -.75, .75}},
- {-1, 1, 1}, {2, 0, 0}},
- /* mirror on right wall */
- {{{1., -.75, .75}, {1., .75, .75}, {1., .75, -.75}, {1., -.75, -.75}},
- {-1, 1, 1}, {-2, 0, 0}},
- };
- int nMirrors = 2;
- void init(void)
- {
- static GLfloat lightpos[] = {.5, .75, 1.5, 1};
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
- glEnable(GL_CULL_FACE);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- cone = gluNewQuadric();
- qsphere = gluNewQuadric();
- }
- void make_viewpoint(void)
- {
- if (headsUp) {
- float width = (1 + 2*(draw_passes/nMirrors)) * 1.25;
- float height = (width / tan((30./360.) * (2.*M_PI))) + 1;
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(60, 1, height - 3, height + 3);
- gluLookAt(0, height, 0,
- 0, 0, 0,
- 0, 0, 1);
- } else {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(60, 1, .01, 4 + 2*(draw_passes / nMirrors));
- gluLookAt(-2, 0, .75,
- 0, 0, 0,
- 0, 1, 0);
- }
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
- void reshape(GLsizei w, GLsizei h)
- {
- glViewport(0, 0, w, h);
- make_viewpoint();
- }
- void draw_room(void)
- {
- /* material for the walls, floor, ceiling */
- static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f};
- glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
- glBegin(GL_QUADS);
-
- /* floor */
- glNormal3f(0, 1, 0);
- glVertex3f(-1, -1, 1);
- glVertex3f(1, -1, 1);
- glVertex3f(1, -1, -1);
- glVertex3f(-1, -1, -1);
- /* ceiling */
- glNormal3f(0, -1, 0);
- glVertex3f(-1, 1, -1);
- glVertex3f(1, 1, -1);
- glVertex3f(1, 1, 1);
- glVertex3f(-1, 1, 1);
- /* left wall */
- glNormal3f(1, 0, 0);
- glVertex3f(-1, -1, -1);
- glVertex3f(-1, 1, -1);
- glVertex3f(-1, 1, 1);
- glVertex3f(-1, -1, 1);
- /* right wall */
- glNormal3f(-1, 0, 0);
- glVertex3f(1, -1, 1);
- glVertex3f(1, 1, 1);
- glVertex3f(1, 1, -1);
- glVertex3f(1, -1, -1);
- /* far wall */
- glNormal3f(0, 0, 1);
- glVertex3f(-1, -1, -1);
- glVertex3f(1, -1, -1);
- glVertex3f(1, 1, -1);
- glVertex3f(-1, 1, -1);
- /* back wall */
- glNormal3f(0, 0, -1);
- glVertex3f(-1, 1, 1);
- glVertex3f(1, 1, 1);
- glVertex3f(1, -1, 1);
- glVertex3f(-1, -1, 1);
- glEnd();
- }
- void draw_cone(void)
- {
- static GLfloat cone_mat[] = {0.f, .5f, 1.f, 1.f};
- glPushMatrix();
- glTranslatef(0, -1, 0);
- glRotatef(-90, 1, 0, 0);
- glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
- gluCylinder(cone, .3, 0, 1.25, 20, 1);
- glPopMatrix();
- }
- void draw_sphere(GLdouble secs)
- {
- static GLfloat sphere_mat[] = {1.f, .5f, 0.f, 1.f};
- GLfloat angle;
- /* one revolution every 10 seconds... */
- secs = secs - 10.*trunc(secs / 10.);
- angle = (secs/10.) * (360.);
- glPushMatrix();
- glTranslatef(0, -.3, 0);
- glRotatef(angle, 0, 1, 0);
- glTranslatef(.6, 0, 0);
- glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
- gluSphere(qsphere, .3, 20, 20);
- glPopMatrix();
- }
- GLdouble get_secs(void)
- {
- return glutGet(GLUT_ELAPSED_TIME) / 1000.0;
- }
- void draw_mirror(Mirror *m)
- {
- glBegin(GL_QUADS);
- glVertex3fv(m->verts[0]);
- glVertex3fv(m->verts[1]);
- glVertex3fv(m->verts[2]);
- glVertex3fv(m->verts[3]);
- glEnd();
- }
- /* A note on matrix management: it would be easier to use push and
- * pop to save and restore the matrices, but the projection matrix stack
- * is very shallow, so we just undo what we did. In the extreme this
- * could lead to mathematic error. */
- GLenum reflect_through_mirror(Mirror *m, GLenum cullFace)
- {
- GLenum newCullFace = ((cullFace == GL_FRONT) ? GL_BACK : GL_FRONT);
- glMatrixMode(GL_PROJECTION);
- glScalef(m->scale[0], m->scale[1], m->scale[2]);
- glTranslatef(m->trans[0], m->trans[1], m->trans[2]);
- glMatrixMode(GL_MODELVIEW);
- /* must flip the cull face since reflection reverses the orientation
- * of the polygons */
- glCullFace(newCullFace);
- return newCullFace;
- }
- void undo_reflect_through_mirror(Mirror *m, GLenum cullFace)
- {
- glMatrixMode(GL_PROJECTION);
- glTranslatef(-m->trans[0], -m->trans[1], -m->trans[2]);
- glScalef(1./m->scale[0], 1./m->scale[1], 1./m->scale[2]);
- glMatrixMode(GL_MODELVIEW);
- glCullFace(cullFace);
- }
- void draw_scene(GLdouble secs, int passes, GLenum cullFace,
- GLuint stencilVal, GLuint mirror)
- {
- GLenum newCullFace;
- int passesPerMirror, passesPerMirrorRem;
- unsigned int curMirror, drawMirrors;
- int i;
- /* one pass to draw the real scene */
- passes--;
- /* only draw in my designated locations */
- glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff);
- /* draw things which may obscure the mirrors first */
- draw_sphere(secs);
- draw_cone();
- /* now draw the appropriate number of mirror reflections. for
- * best results, we perform a depth-first traversal by allocating
- * a number of passes for each of the mirrors. */
- if (mirror != 0xffffffff) {
- passesPerMirror = passes / (nMirrors - 1);
- passesPerMirrorRem = passes % (nMirrors - 1);
- if (passes > nMirrors - 1) drawMirrors = nMirrors - 1;
- else drawMirrors = passes;
- } else {
- /* mirror == -1 means that this is the initial scene (there was no
- * mirror) */
- passesPerMirror = passes / nMirrors;
- passesPerMirrorRem = passes % nMirrors;
- if (passes > nMirrors) drawMirrors = nMirrors;
- else drawMirrors = passes;
- }
- for (i = 0; drawMirrors > 0; i++) {
- curMirror = i % nMirrors;
- if (curMirror == mirror) continue;
- drawMirrors--;
- /* draw mirror into stencil buffer but not color or depth buffers */
- glColorMask(0, 0, 0, 0);
- glDepthMask(0);
- glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
- draw_mirror(&mirrors[curMirror]);
- glColorMask(1, 1, 1, 1);
- glDepthMask(1);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- /* draw reflected scene */
- newCullFace = reflect_through_mirror(&mirrors[curMirror], cullFace);
- if (passesPerMirrorRem) {
- draw_scene(secs, passesPerMirror + 1, newCullFace, stencilVal + 1,
- curMirror);
- passesPerMirrorRem--;
- } else {
- draw_scene(secs, passesPerMirror, newCullFace, stencilVal + 1,
- curMirror);
- }
- undo_reflect_through_mirror(&mirrors[curMirror], cullFace);
- /* back to our stencil value */
- glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff);
- }
- draw_room();
- }
- void draw(void)
- {
- GLenum err;
- GLfloat secs = get_secs();
-
- glDisable(GL_STENCIL_TEST);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
- if (!headsUp) glEnable(GL_STENCIL_TEST);
- draw_scene(secs, draw_passes, GL_BACK, 0, (unsigned)-1);
- glDisable(GL_STENCIL_TEST);
- if (headsUp) {
- /* draw a red floor on the original scene */
- glDisable(GL_LIGHTING);
- glBegin(GL_QUADS);
- glColor3f(1, 0, 0);
- glVertex3f(-1, -.95, 1);
- glVertex3f(1, -.95, 1);
- glVertex3f(1, -.95, -1);
- glVertex3f(-1, -.95, -1);
- glEnd();
- glEnable(GL_LIGHTING);
- }
- err = glGetError();
- if (err != GL_NO_ERROR) printf("Error: %sn", gluErrorString(err));
-
- glutSwapBuffers();
- }
- /* ARGSUSED1 */
- void key(unsigned char key, int x, int y)
- {
- switch(key) {
- case '.': case '>': case '+': case '=':
- draw_passes++;
- printf("Passes = %dn", draw_passes);
- make_viewpoint();
- break;
- case ',': case '<': case '-': case '_':
- draw_passes--;
- if (draw_passes < 1) draw_passes = 1;
- printf("Passes = %dn", draw_passes);
- make_viewpoint();
- break;
- case 'h': case 'H':
- /* heads up mode */
- headsUp = (headsUp == 0);
- make_viewpoint();
- break;
- case 27:
- exit(0);
- }
- }
- #define MIN_COLOR_BITS 4
- #define MIN_DEPTH_BITS 8
- main(int argc, char *argv[])
- {
- glutInit(&argc, argv);
- glutInitWindowSize(256, 256);
- glutInitWindowPosition(0, 0);
- if (argc > 1) {
- glutInitDisplayString("samples stencil>=3 rgb depth");
- } else {
- glutInitDisplayString("samples stencil>=3 rgb double depth");
- }
- glutCreateWindow(argv[0]);
- glutDisplayFunc(draw);
- glutIdleFunc(draw);
- glutKeyboardFunc(key);
- glutReshapeFunc(reshape);
- init();
- glutMainLoop();
- return 0;
- }