summaryrefslogtreecommitdiff
path: root/progs/tests/dinoshade.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/tests/dinoshade.c')
-rw-r--r--progs/tests/dinoshade.c912
1 files changed, 0 insertions, 912 deletions
diff --git a/progs/tests/dinoshade.c b/progs/tests/dinoshade.c
deleted file mode 100644
index fb7c3f4535..0000000000
--- a/progs/tests/dinoshade.c
+++ /dev/null
@@ -1,912 +0,0 @@
-
-/* 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() */
-#include <stddef.h> /* for ptrdiff_t, referenced by GL.h when GL_GLEXT_LEGACY defined */
-#ifdef _WIN32
-#include <windows.h>
-#endif
-#define GL_GLEXT_LEGACY
-#include <GL/glew.h> /* OpenGL Utility Toolkit header */
-#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++) {
-#if 1 /* weird, but seems to be legal */
- /* 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);
-#else /* the nice way of doing it */
- /* 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 % count][1] - data[(i - 1 + count) % count][1];
- dy = data[(i - 1 + count) % count][0] - data[i % count][0];
- len = sqrt(dx * dx + dy * dy);
- glNormal3f(dx / len, dy / len, 0.0);
- /* 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);
-#endif
- }
- 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 * 10 + minor >= 11;
- 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");
- glewInit();
-
- 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. */
-}