static void drawModel(void) { switch(currentModel) { case MOD_DINO: drawDinosaur(); break; case MOD_SPHERE: glMaterialfv(GL_FRONT, GL_DIFFUSE, blueMaterial); glutSolidSphere(6.0, 15, 15); break; case MOD_CUBE: glMaterialfv(GL_FRONT, GL_DIFFUSE, redMaterial); glutSolidCube(6.0); break; case MOD_ICO: glMaterialfv(GL_FRONT, GL_DIFFUSE, purpleMaterial); glPushMatrix(); glEnable(GL_NORMALIZE); glScalef(7.0, 7.0, 7.0); glutSolidIcosahedron(); glDisable(GL_NORMALIZE); glPopMatrix(); break; } }
void logs(void) { static GLUquadricObj *quadric; if (!quadric) { quadric = gluNewQuadric(); glNewList(100, GL_COMPILE); gluQuadricOrientation(quadric, GLU_OUTSIDE); glTranslatef(0.f, 0.f, -2.f); gluCylinder(quadric, .5, .5, 4., 5, 1); glTranslatef(0.f, 0.f, 4.f); gluDisk(quadric, 0., .5, 10, 1); glTranslatef(0.f, 0.f, -4.f); gluQuadricOrientation(quadric, GLU_INSIDE); gluDisk(quadric, 0., .5, 10, 1); glEndList(); } glPushMatrix(); glTranslatef(0.f, -.5f, 0.f); glColor3f(.55f, .14f, .14f); glPushMatrix(); glRotatef(55., 0., 1., 0.); glCallList(100); glPopMatrix(); glPushMatrix(); glRotatef(-55., 0., 1., 0.); glCallList(100); glPopMatrix(); if (marshmallow) { glPushMatrix(); glColor4f(1.f, 1.f, 1.f, 1.f); glTranslatef(0.f, 1.7f, 0.f); glRotatef(45.f, 0.f, 0.f, 1.f); glRotatef(90.f, 0.f, 1.f, 0.f); glScalef(1., 1., .25f); glCallList(100); glPopMatrix(); glPushMatrix(); glColor4f(.1f, .1f, .1f, 1.f); glTranslatef(1.5f, 3.4f, 0.f); glRotatef(45.f, 0.f, 0.f, 1.f); glRotatef(90.f, 0.f, 1.f, 0.f); glScalef(.2f, .2f, 1.f); glCallList(100); glPopMatrix(); if (marshmallow == 2) { extern void drawDinosaur(void); glDisable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(10.f, 0.f, 0.f); glRotatef(180.f, 0.f, 1.f, 0.f); glScalef(.5f, .5f, .5f); drawDinosaur(); glPopMatrix(); } } glPopMatrix(); }
void redraw(void) { if (useStencil) { /* Clear; default stencil clears to zero. */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } else { /* Not using stencil; just clear color and depth. */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } glPushMatrix(); /* Perform scene rotations based on user mouse input. */ glRotatef(angle2, 1.0, 0.0, 0.0); glRotatef(angle, 0.0, 1.0, 0.0); /* Translate the dinosaur to be at (0,0,0). */ glTranslatef(-8, -8, -bodyWidth / 2); glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition); glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition); if (useStencil) { /* We can eliminate the visual "artifact" of seeing the "flipped" dinosaur underneath the floor by using stencil. The idea is draw the floor without color or depth update but so that a stencil value of one is where the floor will be. Later when rendering the dinosaur reflection, we will only update pixels with a stencil value of 1 to make sure the reflection only lives on the floor, not below the floor. */ /* Don't update color or depth. */ glDisable(GL_DEPTH_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* Draw 1 into the stencil buffer. */ glEnable(GL_STENCIL_TEST); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, 0xffffffff); /* Now render floor; floor pixels just get their stencil set to 1. */ drawFloor(); /* Re-enable update of color and depth. */ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_DEPTH_TEST); /* Now, only render where stencil is set to 1. */ glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } glPushMatrix(); /* The critical reflection step: Reflect dinosaur through the floor (the Y=0 plane) to make a relection. */ glScalef(1.0, -1.0, 1.0); /* Position lights now in reflected space. */ glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition); glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition); /* XXX Ugh, unfortunately the back face culling reverses when we reflect the dinosaur. Easy solution is just disable back face culling for rendering the reflection. Also, the normals for lighting get screwed up by the scale; enabled normalize to ensure normals are still properly normalized despite the scaling. We could have fixed the dinosaur rendering code, but this is more expedient. */ glEnable(GL_NORMALIZE); glCullFace(GL_FRONT); /* Draw the reflected dinosaur. */ drawDinosaur(); /* Disable noramlize again and re-enable back face culling. */ glDisable(GL_NORMALIZE); glCullFace(GL_BACK); glPopMatrix(); /* Restore light positions on returned from reflected space. */ glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition); glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition); if (useStencil) { /* Don't want to be using stenciling for drawing the actual dinosaur (not its reflection) and the floor. */ glDisable(GL_STENCIL_TEST); } /* Back face culling will get used to only draw either the top or the bottom floor. This let's us get a floor with two distinct appearances. The top floor surface is reflective and kind of red. The bottom floor surface is not reflective and blue. */ /* Draw "top" of floor. Use blending to blend in reflection. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.7, 0.0, 0.0, 0.3); drawFloor(); glDisable(GL_BLEND); /* Draw "bottom" of floor in blue. */ glFrontFace(GL_CW); /* Switch face orientation. */ glColor4f(0.1, 0.1, 0.7, 1.0); drawFloor(); glFrontFace(GL_CCW); /* Draw "actual" dinosaur, not its reflection. */ drawDinosaur(); glPopMatrix(); glutSwapBuffers(); }
static void redraw(void) { int start = 0, end = 0; if (reportSpeed) { start = glutGet(GLUT_ELAPSED_TIME); } /* Clear; default stencil clears to zero. */ if ((stencilReflection && renderReflection) || (stencilShadow && renderShadow)) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } else { /* Avoid clearing stencil when not using it. */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } /* Reposition the light source. */ lightPosition[0] = 12*cos(lightAngle); lightPosition[1] = lightHeight; lightPosition[2] = 12*sin(lightAngle); if (directionalLight) { lightPosition[3] = 0.0; } else { lightPosition[3] = 1.0; } shadowMatrix(floorShadow, floorPlane, lightPosition); glPushMatrix(); /* Perform scene rotations based on user mouse input. */ glRotatef(angle2, 1.0, 0.0, 0.0); glRotatef(angle, 0.0, 1.0, 0.0); /* Tell GL new light source position. */ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); if (renderReflection) { if (stencilReflection) { /* We can eliminate the visual "artifact" of seeing the "flipped" dinosaur underneath the floor by using stencil. The idea is draw the floor without color or depth update but so that a stencil value of one is where the floor will be. Later when rendering the dinosaur reflection, we will only update pixels with a stencil value of 1 to make sure the reflection only lives on the floor, not below the floor. */ /* Don't update color or depth. */ glDisable(GL_DEPTH_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* Draw 1 into the stencil buffer. */ glEnable(GL_STENCIL_TEST); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, 0xffffffff); /* Now render floor; floor pixels just get their stencil set to 1. */ drawFloor(); /* Re-enable update of color and depth. */ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_DEPTH_TEST); /* Now, only render where stencil is set to 1. */ glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } glPushMatrix(); /* The critical reflection step: Reflect dinosaur through the floor (the Y=0 plane) to make a relection. */ glScalef(1.0, -1.0, 1.0); /* Reflect the light position. */ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); /* To avoid our normals getting reversed and hence botched lighting on the reflection, turn on normalize. */ glEnable(GL_NORMALIZE); glCullFace(GL_FRONT); /* Draw the reflected dinosaur. */ drawDinosaur(); /* Disable noramlize again and re-enable back face culling. */ glDisable(GL_NORMALIZE); glCullFace(GL_BACK); glPopMatrix(); /* Switch back to the unreflected light position. */ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); if (stencilReflection) { glDisable(GL_STENCIL_TEST); } } /* Back face culling will get used to only draw either the top or the bottom floor. This let's us get a floor with two distinct appearances. The top floor surface is reflective and kind of red. The bottom floor surface is not reflective and blue. */ /* Draw "bottom" of floor in blue. */ glFrontFace(GL_CW); /* Switch face orientation. */ glColor4f(0.1, 0.1, 0.7, 1.0); drawFloor(); glFrontFace(GL_CCW); if (renderShadow) { if (stencilShadow) { /* Draw the floor with stencil value 3. This helps us only draw the shadow once per floor pixel (and only on the floor pixels). */ glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 3, 0xffffffff); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); } } /* Draw "top" of floor. Use blending to blend in reflection. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.7, 0.0, 0.0, 0.3); glColor4f(1.0, 1.0, 1.0, 0.3); drawFloor(); glDisable(GL_BLEND); if (renderDinosaur) { /* Draw "actual" dinosaur, not its reflection. */ drawDinosaur(); } if (renderShadow) { /* Render the projected shadow. */ if (stencilShadow) { /* Now, only render where stencil is set above 2 (ie, 3 where the top floor is). Update stencil with 2 where the shadow gets drawn so we don't redraw (and accidently reblend) the shadow). */ glStencilFunc(GL_LESS, 2, 0xffffffff); /* draw if ==1 */ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); } /* To eliminate depth buffer artifacts, we use polygon offset to raise the depth of the projected shadow slightly so that it does not depth buffer alias with the floor. */ if (offsetShadow) { switch (polygonOffsetVersion) { case EXTENSION: #ifdef GL_EXT_polygon_offset glEnable(GL_POLYGON_OFFSET_EXT); break; #endif #ifdef GL_VERSION_1_1 case ONE_DOT_ONE: glEnable(GL_POLYGON_OFFSET_FILL); break; #endif case MISSING: /* Oh well. */ break; } } /* Render 50% black shadow color on top of whatever the floor appareance is. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_LIGHTING); /* Force the 50% black. */ glColor4f(0.0, 0.0, 0.0, 0.5); glPushMatrix(); /* Project the shadow. */ glMultMatrixf((GLfloat *) floorShadow); drawDinosaur(); glPopMatrix(); glDisable(GL_BLEND); glEnable(GL_LIGHTING); if (offsetShadow) { switch (polygonOffsetVersion) { #ifdef GL_EXT_polygon_offset case EXTENSION: glDisable(GL_POLYGON_OFFSET_EXT); break; #endif #ifdef GL_VERSION_1_1 case ONE_DOT_ONE: glDisable(GL_POLYGON_OFFSET_FILL); break; #endif case MISSING: /* Oh well. */ break; } } if (stencilShadow) { glDisable(GL_STENCIL_TEST); } } glPushMatrix(); glDisable(GL_LIGHTING); glColor3f(1.0, 1.0, 0.0); if (directionalLight) { /* Draw an arrowhead. */ glDisable(GL_CULL_FACE); glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]); glRotatef(lightAngle * -180.0 / M_PI, 0, 1, 0); glRotatef(atan(lightHeight/12) * 180.0 / M_PI, 0, 0, 1); glBegin(GL_TRIANGLE_FAN); glVertex3f(0, 0, 0); glVertex3f(2, 1, 1); glVertex3f(2, -1, 1); glVertex3f(2, -1, -1); glVertex3f(2, 1, -1); glVertex3f(2, 1, 1); glEnd(); /* Draw a white line from light direction. */ glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINES); glVertex3f(0, 0, 0); glVertex3f(5, 0, 0); glEnd(); glEnable(GL_CULL_FACE); } else { /* Draw a yellow ball at the light source. */ glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]); glutSolidSphere(1.0, 5, 5); } glEnable(GL_LIGHTING); glPopMatrix(); glPopMatrix(); if (reportSpeed) { glFinish(); end = glutGet(GLUT_ELAPSED_TIME); printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start); fflush(stdout); } glutSwapBuffers(); }