+ if (stencilReflection) {\r
+ glDisable(GL_STENCIL_TEST);\r
+ }\r
+ }\r
+\r
+ /* Back face culling will get used to only draw either the top or the\r
+ bottom floor. This let's us get a floor with two distinct\r
+ appearances. The top floor surface is reflective and kind of red.\r
+ The bottom floor surface is not reflective and blue. */\r
+\r
+ /* Draw "bottom" of floor in blue. */\r
+ glFrontFace(GL_CW); /* Switch face orientation. */\r
+ glColor4f(0.1, 0.1, 0.7, 1.0);\r
+ drawFloor();\r
+ glFrontFace(GL_CCW);\r
+\r
+ if (renderShadow) {\r
+ if (stencilShadow) {\r
+ /* Draw the floor with stencil value 3. This helps us only\r
+ draw the shadow once per floor pixel (and only on the\r
+ floor pixels). */\r
+ glEnable(GL_STENCIL_TEST);\r
+ glStencilFunc(GL_ALWAYS, 3, 0xffffffff);\r
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);\r
+ }\r
+ }\r
+\r
+ /* Draw "top" of floor. Use blending to blend in reflection. */\r
+ glEnable(GL_BLEND);\r
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
+ glColor4f(0.7, 0.0, 0.0, 0.3);\r
+ glColor4f(1.0, 1.0, 1.0, 0.3);\r
+ drawFloor();\r
+ glDisable(GL_BLEND);\r
+\r
+ if (renderDinosaur) {\r
+ /* Draw "actual" dinosaur, not its reflection. */\r
+ drawDinosaur();\r
+ }\r
+\r
+ if (renderShadow) {\r
+\r
+ /* Render the projected shadow. */\r
+\r
+ if (stencilShadow) {\r
+\r
+ /* Now, only render where stencil is set above 2 (ie, 3 where\r
+ the top floor is). Update stencil with 2 where the shadow\r
+ gets drawn so we don't redraw (and accidently reblend) the\r
+ shadow). */\r
+ glStencilFunc(GL_LESS, 2, 0xffffffff); /* draw if ==1 */\r
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);\r
+ }\r
+\r
+ /* To eliminate depth buffer artifacts, we use polygon offset\r
+ to raise the depth of the projected shadow slightly so\r
+ that it does not depth buffer alias with the floor. */\r
+ if (offsetShadow) {\r
+ switch (polygonOffsetVersion) {\r
+ case EXTENSION:\r
+#ifdef GL_EXT_polygon_offset\r
+ glEnable(GL_POLYGON_OFFSET_EXT);\r
+ break;\r
+#endif\r
+#ifdef GL_VERSION_1_1\r
+ case ONE_DOT_ONE:\r
+ glEnable(GL_POLYGON_OFFSET_FILL);\r
+ break;\r
+#endif\r
+ case MISSING:\r
+ /* Oh well. */\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* Render 50% black shadow color on top of whatever the\r
+ floor appareance is. */\r
+ glEnable(GL_BLEND);\r
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
+ glDisable(GL_LIGHTING); /* Force the 50% black. */\r
+ glColor4f(0.0, 0.0, 0.0, 0.5);\r
+\r
+ glPushMatrix();\r
+ /* Project the shadow. */\r
+ glMultMatrixf((GLfloat *) floorShadow);\r
+ drawDinosaur();\r
+ glPopMatrix();\r
+\r
+ glDisable(GL_BLEND);\r
+ glEnable(GL_LIGHTING);\r
+\r
+ if (offsetShadow) {\r
+ switch (polygonOffsetVersion) {\r
+#ifdef GL_EXT_polygon_offset\r
+ case EXTENSION:\r
+ glDisable(GL_POLYGON_OFFSET_EXT);\r
+ break;\r
+#endif\r
+#ifdef GL_VERSION_1_1\r
+ case ONE_DOT_ONE:\r
+ glDisable(GL_POLYGON_OFFSET_FILL);\r
+ break;\r
+#endif\r
+ case MISSING:\r
+ /* Oh well. */\r
+ break;\r
+ }\r
+ }\r
+ if (stencilShadow) {\r
+ glDisable(GL_STENCIL_TEST);\r
+ }\r
+ }\r
+\r
+ glPushMatrix();\r
+ glDisable(GL_LIGHTING);\r
+ glColor3f(1.0, 1.0, 0.0);\r
+ if (directionalLight) {\r
+ /* Draw an arrowhead. */\r
+ glDisable(GL_CULL_FACE);\r
+ glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);\r
+ glRotatef(lightAngle * -180.0 / M_PI, 0, 1, 0);\r
+ glRotatef(atan(lightHeight/12) * 180.0 / M_PI, 0, 0, 1);\r
+ glBegin(GL_TRIANGLE_FAN);\r
+ glVertex3f(0, 0, 0);\r
+ glVertex3f(2, 1, 1);\r
+ glVertex3f(2, -1, 1);\r
+ glVertex3f(2, -1, -1);\r
+ glVertex3f(2, 1, -1);\r
+ glVertex3f(2, 1, 1);\r
+ glEnd();\r
+ /* Draw a white line from light direction. */\r
+ glColor3f(1.0, 1.0, 1.0);\r
+ glBegin(GL_LINES);\r
+ glVertex3f(0, 0, 0);\r
+ glVertex3f(5, 0, 0);\r
+ glEnd();\r
+ glEnable(GL_CULL_FACE);\r
+ } else {\r
+ /* Draw a yellow ball at the light source. */\r
+ glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);\r
+ glutSolidSphere(1.0, 5, 5);\r
+ }\r
+ glEnable(GL_LIGHTING);\r
+ glPopMatrix();\r