| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 | 
							- 
 - /* Copyright (c) Mark J. Kilgard, 1994, 1997.  */
 - 
 - /* This program is freely distributable without licensing fees 
 -    and is provided without guarantee or warrantee expressed or 
 -    implied. This program is -not- in the public domain. */
 - 
 - /* Example for PC game developers to show how to *combine* texturing,
 -    reflections, and projected shadows all in real-time with OpenGL.
 -    Robust reflections use stenciling.  Robust projected shadows
 -    use both stenciling and polygon offset.  PC game programmers
 -    should realize that neither stenciling nor polygon offset are 
 -    supported by Direct3D, so these real-time rendering algorithms
 -    are only really viable with OpenGL. 
 -    
 -    The program has modes for disabling the stenciling and polygon
 -    offset uses.  It is worth running this example with these features
 -    toggled off so you can see the sort of artifacts that result.
 -    
 -    Notice that the floor texturing, reflections, and shadowing
 -    all co-exist properly. */
 - 
 - /* When you run this program:  Left mouse button controls the
 -    view.  Middle mouse button controls light position (left &
 -    right rotates light around dino; up & down moves light
 -    position up and down).  Right mouse button pops up menu. */
 - 
 - /* Check out the comments in the "redraw" routine to see how the
 -    reflection blending and surface stenciling is done.  You can
 -    also see in "redraw" how the projected shadows are rendered,
 -    including the use of stenciling and polygon offset. */
 - 
 - /* This program is derived from glutdino.c */
 - 
 - /* Compile: cc -o dinoshade dinoshade.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
 - 
 - #include <stdio.h>
 - #include <stdlib.h>
 - #include <string.h>
 - #include <math.h>       /* for cos(), sin(), and sqrt() */
 - #ifdef __VMS
 - # include <stddef.h>	/* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
 - #else
 - # include <malloc.h>	/* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
 - #endif
 - #ifdef _WIN32
 - #include <windows.h>
 - #endif
 - #define GL_GLEXT_LEGACY
 - #include <GL/glut.h>    /* OpenGL Utility Toolkit header */
 - 
 - /* Some <math.h> files do not define M_PI... */
 - #ifndef M_PI
 - #define M_PI 3.14159265358979323846
 - #endif
 - 
 - /* Variable controlling various rendering modes. */
 - static int stencilReflection = 1, stencilShadow = 1, offsetShadow = 1;
 - static int renderShadow = 1, renderDinosaur = 1, renderReflection = 1;
 - static int linearFiltering = 0, useMipmaps = 0, useTexture = 1;
 - static int reportSpeed = 0;
 - static int animation = 1;
 - static GLboolean lightSwitch = GL_TRUE;
 - static int directionalLight = 1;
 - static int forceExtension = 0;
 - 
 - /* Time varying or user-controled variables. */
 - static float jump = 0.0;
 - static float lightAngle = 0.0, lightHeight = 20;
 - GLfloat angle = -150;   /* in degrees */
 - GLfloat angle2 = 30;   /* in degrees */
 - 
 - int moving, startx, starty;
 - int lightMoving = 0, lightStartX, lightStartY;
 - 
 - enum {
 -   MISSING, EXTENSION, ONE_DOT_ONE
 - };
 - int polygonOffsetVersion;
 - 
 - static GLdouble bodyWidth = 3.0;
 - /* *INDENT-OFF* */
 - static GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
 -   {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
 -   {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
 -   {1, 2} };
 - static GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
 -   {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
 -   {13, 9}, {11, 11}, {9, 11} };
 - static GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
 -   {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
 - static GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
 -   {9.6, 15.25}, {9, 15.25} };
 - static GLfloat lightPosition[4];
 - static GLfloat lightColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
 - static GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
 - /* *INDENT-ON* */
 - 
 - /* Nice floor texture tiling pattern. */
 - static char *circles[] = {
 -   "....xxxx........",
 -   "..xxxxxxxx......",
 -   ".xxxxxxxxxx.....",
 -   ".xxx....xxx.....",
 -   "xxx......xxx....",
 -   "xxx......xxx....",
 -   "xxx......xxx....",
 -   "xxx......xxx....",
 -   ".xxx....xxx.....",
 -   ".xxxxxxxxxx.....",
 -   "..xxxxxxxx......",
 -   "....xxxx........",
 -   "................",
 -   "................",
 -   "................",
 -   "................",
 - };
 - 
 - static void
 - makeFloorTexture(void)
 - {
 -   GLubyte floorTexture[16][16][3];
 -   GLubyte *loc;
 -   int s, t;
 - 
 -   /* Setup RGB image for the texture. */
 -   loc = (GLubyte*) floorTexture;
 -   for (t = 0; t < 16; t++) {
 -     for (s = 0; s < 16; s++) {
 -       if (circles[t][s] == 'x') {
 - 	/* Nice green. */
 -         loc[0] = 0x1f;
 -         loc[1] = 0x8f;
 -         loc[2] = 0x1f;
 -       } else {
 - 	/* Light gray. */
 -         loc[0] = 0xaa;
 -         loc[1] = 0xaa;
 -         loc[2] = 0xaa;
 -       }
 -       loc += 3;
 -     }
 -   }
 - 
 -   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 - 
 -   if (useMipmaps) {
 -     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 -       GL_LINEAR_MIPMAP_LINEAR);
 -     gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
 -       GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
 -   } else {
 -     if (linearFiltering) {
 -       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 -     } else {
 -       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 -     }
 -     glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
 -       GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
 -   }
 - }
 - 
 - enum {
 -   X, Y, Z, W
 - };
 - enum {
 -   A, B, C, D
 - };
 - 
 - /* Create a matrix that will project the desired shadow. */
 - void
 - shadowMatrix(GLfloat shadowMat[4][4],
 -   GLfloat groundplane[4],
 -   GLfloat lightpos[4])
 - {
 -   GLfloat dot;
 - 
 -   /* Find dot product between light position vector and ground plane normal. */
 -   dot = groundplane[X] * lightpos[X] +
 -     groundplane[Y] * lightpos[Y] +
 -     groundplane[Z] * lightpos[Z] +
 -     groundplane[W] * lightpos[W];
 - 
 -   shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
 -   shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
 -   shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
 -   shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
 - 
 -   shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
 -   shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
 -   shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
 -   shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
 - 
 -   shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
 -   shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
 -   shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
 -   shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
 - 
 -   shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
 -   shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
 -   shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
 -   shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
 - 
 - }
 - 
 - /* Find the plane equation given 3 points. */
 - void
 - findPlane(GLfloat plane[4],
 -   GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
 - {
 -   GLfloat vec0[3], vec1[3];
 - 
 -   /* Need 2 vectors to find cross product. */
 -   vec0[X] = v1[X] - v0[X];
 -   vec0[Y] = v1[Y] - v0[Y];
 -   vec0[Z] = v1[Z] - v0[Z];
 - 
 -   vec1[X] = v2[X] - v0[X];
 -   vec1[Y] = v2[Y] - v0[Y];
 -   vec1[Z] = v2[Z] - v0[Z];
 - 
 -   /* find cross product to get A, B, and C of plane equation */
 -   plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
 -   plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
 -   plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
 - 
 -   plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
 - }
 - 
 - void
 - extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
 -   GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
 - {
 -   static GLUtriangulatorObj *tobj = NULL;
 -   GLdouble vertex[3], dx, dy, len;
 -   int i;
 -   int count = (int) (dataSize / (2 * sizeof(GLfloat)));
 - 
 -   if (tobj == NULL) {
 -     tobj = gluNewTess();  /* create and initialize a GLU
 -                              polygon tesselation object */
 -     gluTessCallback(tobj, GLU_BEGIN, glBegin);
 -     gluTessCallback(tobj, GLU_VERTEX, glVertex2fv);  /* semi-tricky */
 -     gluTessCallback(tobj, GLU_END, glEnd);
 -   }
 -   glNewList(side, GL_COMPILE);
 -   glShadeModel(GL_SMOOTH);  /* smooth minimizes seeing
 -                                tessellation */
 -   gluBeginPolygon(tobj);
 -   for (i = 0; i < count; i++) {
 -     vertex[0] = data[i][0];
 -     vertex[1] = data[i][1];
 -     vertex[2] = 0;
 -     gluTessVertex(tobj, vertex, data[i]);
 -   }
 -   gluEndPolygon(tobj);
 -   glEndList();
 -   glNewList(edge, GL_COMPILE);
 -   glShadeModel(GL_FLAT);  /* flat shade keeps angular hands
 -                              from being "smoothed" */
 -   glBegin(GL_QUAD_STRIP);
 -   for (i = 0; i <= count; i++) {
 -     /* mod function handles closing the edge */
 -     glVertex3f(data[i % count][0], data[i % count][1], 0.0);
 -     glVertex3f(data[i % count][0], data[i % count][1], thickness);
 -     /* Calculate a unit normal by dividing by Euclidean
 -        distance. We * could be lazy and use
 -        glEnable(GL_NORMALIZE) so we could pass in * arbitrary
 -        normals for a very slight performance hit. */
 -     dx = data[(i + 1) % count][1] - data[i % count][1];
 -     dy = data[i % count][0] - data[(i + 1) % count][0];
 -     len = sqrt(dx * dx + dy * dy);
 -     glNormal3f(dx / len, dy / len, 0.0);
 -   }
 -   glEnd();
 -   glEndList();
 -   glNewList(whole, GL_COMPILE);
 -   glFrontFace(GL_CW);
 -   glCallList(edge);
 -   glNormal3f(0.0, 0.0, -1.0);  /* constant normal for side */
 -   glCallList(side);
 -   glPushMatrix();
 -   glTranslatef(0.0, 0.0, thickness);
 -   glFrontFace(GL_CCW);
 -   glNormal3f(0.0, 0.0, 1.0);  /* opposite normal for other side */
 -   glCallList(side);
 -   glPopMatrix();
 -   glEndList();
 - }
 - 
 - /* Enumerants for refering to display lists. */
 - typedef enum {
 -   RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
 -   LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE
 - } displayLists;
 - 
 - static void
 - makeDinosaur(void)
 - {
 -   extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
 -     BODY_SIDE, BODY_EDGE, BODY_WHOLE);
 -   extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
 -     ARM_SIDE, ARM_EDGE, ARM_WHOLE);
 -   extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
 -     LEG_SIDE, LEG_EDGE, LEG_WHOLE);
 -   extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
 -     EYE_SIDE, EYE_EDGE, EYE_WHOLE);
 - }
 - 
 - static void
 - drawDinosaur(void)
 - 
 - {
 -   glPushMatrix();
 -   /* Translate the dinosaur to be at (0,8,0). */
 -   glTranslatef(-8, 0, -bodyWidth / 2);
 -   glTranslatef(0.0, jump, 0.0);
 -   glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
 -   glCallList(BODY_WHOLE);
 -   glTranslatef(0.0, 0.0, bodyWidth);
 -   glCallList(ARM_WHOLE);
 -   glCallList(LEG_WHOLE);
 -   glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
 -   glCallList(ARM_WHOLE);
 -   glTranslatef(0.0, 0.0, -bodyWidth / 4);
 -   glCallList(LEG_WHOLE);
 -   glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
 -   glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
 -   glCallList(EYE_WHOLE);
 -   glPopMatrix();
 - }
 - 
 - static GLfloat floorVertices[4][3] = {
 -   { -20.0, 0.0, 20.0 },
 -   { 20.0, 0.0, 20.0 },
 -   { 20.0, 0.0, -20.0 },
 -   { -20.0, 0.0, -20.0 },
 - };
 - 
 - /* Draw a floor (possibly textured). */
 - static void
 - drawFloor(void)
 - {
 -   glDisable(GL_LIGHTING);
 - 
 -   if (useTexture) {
 -     glEnable(GL_TEXTURE_2D);
 -   }
 - 
 -   glBegin(GL_QUADS);
 -     glTexCoord2f(0.0, 0.0);
 -     glVertex3fv(floorVertices[0]);
 -     glTexCoord2f(0.0, 16.0);
 -     glVertex3fv(floorVertices[1]);
 -     glTexCoord2f(16.0, 16.0);
 -     glVertex3fv(floorVertices[2]);
 -     glTexCoord2f(16.0, 0.0);
 -     glVertex3fv(floorVertices[3]);
 -   glEnd();
 - 
 -   if (useTexture) {
 -     glDisable(GL_TEXTURE_2D);
 -   }
 - 
 -   glEnable(GL_LIGHTING);
 - }
 - 
 - static GLfloat floorPlane[4];
 - static GLfloat floorShadow[4][4];
 - 
 - static void
 - redraw(void)
 - {
 -   int start, end;
 - 
 -   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);
 -   }
 - 
 -   glutSwapBuffers();
 - }
 - 
 - /* ARGSUSED2 */
 - static void
 - mouse(int button, int state, int x, int y)
 - {
 -   if (button == GLUT_LEFT_BUTTON) {
 -     if (state == GLUT_DOWN) {
 -       moving = 1;
 -       startx = x;
 -       starty = y;
 -     }
 -     if (state == GLUT_UP) {
 -       moving = 0;
 -     }
 -   }
 -   if (button == GLUT_MIDDLE_BUTTON) {
 -     if (state == GLUT_DOWN) {
 -       lightMoving = 1;
 -       lightStartX = x;
 -       lightStartY = y;
 -     }
 -     if (state == GLUT_UP) {
 -       lightMoving = 0;
 -     }
 -   }
 - }
 - 
 - /* ARGSUSED1 */
 - static void
 - motion(int x, int y)
 - {
 -   if (moving) {
 -     angle = angle + (x - startx);
 -     angle2 = angle2 + (y - starty);
 -     startx = x;
 -     starty = y;
 -     glutPostRedisplay();
 -   }
 -   if (lightMoving) {
 -     lightAngle += (x - lightStartX)/40.0;
 -     lightHeight += (lightStartY - y)/20.0;
 -     lightStartX = x;
 -     lightStartY = y;
 -     glutPostRedisplay();
 -   }
 - }
 - 
 - /* Advance time varying state when idle callback registered. */
 - static void
 - idle(void)
 - {
 -   static float time = 0.0;
 - 
 -   time = glutGet(GLUT_ELAPSED_TIME) / 500.0;
 - 
 -   jump = 4.0 * fabs(sin(time)*0.5);
 -   if (!lightMoving) {
 -     lightAngle += 0.03;
 -   }
 -   glutPostRedisplay();
 - }
 - 
 - enum {
 -   M_NONE, M_MOTION, M_LIGHT, M_TEXTURE, M_SHADOWS, M_REFLECTION, M_DINOSAUR,
 -   M_STENCIL_REFLECTION, M_STENCIL_SHADOW, M_OFFSET_SHADOW,
 -   M_POSITIONAL, M_DIRECTIONAL, M_PERFORMANCE
 - };
 - 
 - static void
 - controlLights(int value)
 - {
 -   switch (value) {
 -   case M_NONE:
 -     return;
 -   case M_MOTION:
 -     animation = 1 - animation;
 -     if (animation) {
 -       glutIdleFunc(idle);
 -     } else {
 -       glutIdleFunc(NULL);
 -     }
 -     break;
 -   case M_LIGHT:
 -     lightSwitch = !lightSwitch;
 -     if (lightSwitch) {
 -       glEnable(GL_LIGHT0);
 -     } else {
 -       glDisable(GL_LIGHT0);
 -     }
 -     break;
 -   case M_TEXTURE:
 -     useTexture = !useTexture;
 -     break;
 -   case M_SHADOWS:
 -     renderShadow = 1 - renderShadow;
 -     break;
 -   case M_REFLECTION:
 -     renderReflection = 1 - renderReflection;
 -     break;
 -   case M_DINOSAUR:
 -     renderDinosaur = 1 - renderDinosaur;
 -     break;
 -   case M_STENCIL_REFLECTION:
 -     stencilReflection = 1 - stencilReflection;
 -     break;
 -   case M_STENCIL_SHADOW:
 -     stencilShadow = 1 - stencilShadow;
 -     break;
 -   case M_OFFSET_SHADOW:
 -     offsetShadow = 1 - offsetShadow;
 -     break;
 -   case M_POSITIONAL:
 -     directionalLight = 0;
 -     break;
 -   case M_DIRECTIONAL:
 -     directionalLight = 1;
 -     break;
 -   case M_PERFORMANCE:
 -     reportSpeed = 1 - reportSpeed;
 -     break;
 -   }
 -   glutPostRedisplay();
 - }
 - 
 - /* When not visible, stop animating.  Restart when visible again. */
 - static void 
 - visible(int vis)
 - {
 -   if (vis == GLUT_VISIBLE) {
 -     if (animation)
 -       glutIdleFunc(idle);
 -   } else {
 -     if (!animation)
 -       glutIdleFunc(NULL);
 -   }
 - }
 - 
 - /* Press any key to redraw; good when motion stopped and
 -    performance reporting on. */
 - /* ARGSUSED */
 - static void
 - key(unsigned char c, int x, int y)
 - {
 -   if (c == 27) {
 -     exit(0);  /* IRIS GLism, Escape quits. */
 -   }
 -   glutPostRedisplay();
 - }
 - 
 - /* Press any key to redraw; good when motion stopped and
 -    performance reporting on. */
 - /* ARGSUSED */
 - static void
 - special(int k, int x, int y)
 - {
 -   glutPostRedisplay();
 - }
 - 
 - static int
 - supportsOneDotOne(void)
 - {
 -   const char *version;
 -   int major, minor;
 - 
 -   version = (char *) glGetString(GL_VERSION);
 -   if (sscanf(version, "%d.%d", &major, &minor) == 2)
 -     return major >= 1 && minor >= 1;
 -   return 0;            /* OpenGL version string malformed! */
 - }
 - 
 - int
 - main(int argc, char **argv)
 - {
 -   int i;
 - 
 -   glutInit(&argc, argv);
 - 
 -   for (i=1; i<argc; i++) {
 -     if (!strcmp("-linear", argv[i])) {
 -       linearFiltering = 1;
 -     } else if (!strcmp("-mipmap", argv[i])) {
 -       useMipmaps = 1;
 -     } else if (!strcmp("-ext", argv[i])) {
 -       forceExtension = 1;
 -     }
 -   }
 - 
 -   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
 - 
 - #if 0
 -   /* In GLUT 4.0, you'll be able to do this an be sure to
 -      get 2 bits of stencil if the machine has it for you. */
 -   glutInitDisplayString("samples stencil>=2 rgb double depth");
 - #endif
 - 
 -   glutCreateWindow("Shadowy Leapin' Lizards");
 - 
 -   if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {
 -     printf("dinoshade: Sorry, I need at least 2 bits of stencil.\n");
 -     exit(1);
 -   }
 - 
 -   /* Register GLUT callbacks. */
 -   glutDisplayFunc(redraw);
 -   glutMouseFunc(mouse);
 -   glutMotionFunc(motion);
 -   glutVisibilityFunc(visible);
 -   glutKeyboardFunc(key);
 -   glutSpecialFunc(special);
 - 
 -   glutCreateMenu(controlLights);
 - 
 -   glutAddMenuEntry("Toggle motion", M_MOTION);
 -   glutAddMenuEntry("-----------------------", M_NONE);
 -   glutAddMenuEntry("Toggle light", M_LIGHT);
 -   glutAddMenuEntry("Toggle texture", M_TEXTURE);
 -   glutAddMenuEntry("Toggle shadows", M_SHADOWS);
 -   glutAddMenuEntry("Toggle reflection", M_REFLECTION);
 -   glutAddMenuEntry("Toggle dinosaur", M_DINOSAUR);
 -   glutAddMenuEntry("-----------------------", M_NONE);
 -   glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);
 -   glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);
 -   glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);
 -   glutAddMenuEntry("----------------------", M_NONE);
 -   glutAddMenuEntry("Positional light", M_POSITIONAL);
 -   glutAddMenuEntry("Directional light", M_DIRECTIONAL);
 -   glutAddMenuEntry("-----------------------", M_NONE);
 -   glutAddMenuEntry("Toggle performance", M_PERFORMANCE);
 -   glutAttachMenu(GLUT_RIGHT_BUTTON);
 -   makeDinosaur();
 - 
 - #ifdef GL_VERSION_1_1
 -   if (supportsOneDotOne() && !forceExtension) {
 -     polygonOffsetVersion = ONE_DOT_ONE;
 -     glPolygonOffset(-2.0, -9.0);
 -   } else
 - #endif
 -   {
 - #ifdef GL_EXT_polygon_offset
 -   /* check for the polygon offset extension */
 -   if (glutExtensionSupported("GL_EXT_polygon_offset")) {
 -     polygonOffsetVersion = EXTENSION;
 -     glPolygonOffsetEXT(-2.0, -0.002);
 -   } else 
 - #endif
 -     {
 -       polygonOffsetVersion = MISSING;
 -       printf("\ndinoshine: Missing polygon offset.\n");
 -       printf("           Expect shadow depth aliasing artifacts.\n\n");
 -     }
 -   }
 - 
 -   glEnable(GL_CULL_FACE);
 -   glEnable(GL_DEPTH_TEST);
 -   glEnable(GL_TEXTURE_2D);
 -   glLineWidth(3.0);
 - 
 -   glMatrixMode(GL_PROJECTION);
 -   gluPerspective( /* field of view in degree */ 40.0,
 -   /* aspect ratio */ 1.0,
 -     /* Z near */ 20.0, /* Z far */ 100.0);
 -   glMatrixMode(GL_MODELVIEW);
 -   gluLookAt(0.0, 8.0, 60.0,  /* eye is at (0,8,60) */
 -     0.0, 8.0, 0.0,      /* center is at (0,8,0) */
 -     0.0, 1.0, 0.);      /* up is in postivie Y direction */
 - 
 -   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
 -   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
 -   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
 -   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
 -   glEnable(GL_LIGHT0);
 -   glEnable(GL_LIGHTING);
 - 
 -   makeFloorTexture();
 - 
 -   /* Setup floor plane for projected shadow calculations. */
 -   findPlane(floorPlane, floorVertices[1], floorVertices[2], floorVertices[3]);
 - 
 -   glutMainLoop();
 -   return 0;             /* ANSI C requires main to return int. */
 - }
 
 
  |