dinoshade.c
Go to the documentation of this file.
1 
2 /* Copyright (c) Mark J. Kilgard, 1994, 1997. */
3 
4 /* This program is freely distributable without licensing fees
5  and is provided without guarantee or warrantee expressed or
6  implied. This program is -not- in the public domain. */
7 
8 /* Example for PC game developers to show how to *combine* texturing,
9  reflections, and projected shadows all in real-time with OpenGL.
10  Robust reflections use stenciling. Robust projected shadows
11  use both stenciling and polygon offset. PC game programmers
12  should realize that neither stenciling nor polygon offset are
13  supported by Direct3D, so these real-time rendering algorithms
14  are only really viable with OpenGL.
15 
16  The program has modes for disabling the stenciling and polygon
17  offset uses. It is worth running this example with these features
18  toggled off so you can see the sort of artifacts that result.
19 
20  Notice that the floor texturing, reflections, and shadowing
21  all co-exist properly. */
22 
23 /* When you run this program: Left mouse button controls the
24  view. Middle mouse button controls light position (left &
25  right rotates light around dino; up & down moves light
26  position up and down). Right mouse button pops up menu. */
27 
28 /* Check out the comments in the "redraw" routine to see how the
29  reflection blending and surface stenciling is done. You can
30  also see in "redraw" how the projected shadows are rendered,
31 
32  including the use of stenciling and polygon offset. */
33 
34 /* This program is derived from glutdino.c */
35 
36 /* Compile: cc -o dinoshade dinoshade.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h> /* for cos(), sin(), and sqrt() */
42 #include <GL/glut.h> /* OpenGL Utility Toolkit header */
43 
44 /* Some <math.h> files do not define M_PI... */
45 #ifndef M_PI
46 #define M_PI 3.14159265
47 #endif
48 
49 /* Variable controlling various rendering modes. */
50 static int stencilReflection = 1, stencilShadow = 1, offsetShadow = 1;
51 static int renderShadow = 1, renderDinosaur = 1, renderReflection = 1;
52 static int linearFiltering = 0, useMipmaps = 0, useTexture = 1;
53 static int reportSpeed = 0;
54 static int animation = 1;
55 static GLboolean lightSwitch = GL_TRUE;
56 static int directionalLight = 1;
57 static int forceExtension = 0;
58 
59 /* Time varying or user-controled variables. */
60 static float jump = 0.0;
61 static float lightAngle = 0.0, lightHeight = 20;
62 GLfloat angle = -150; /* in degrees */
63 GLfloat angle2 = 30; /* in degrees */
64 
67 
68 enum {
70 };
72 
73 static GLdouble bodyWidth = 3.0;
74 /* *INDENT-OFF* */
75 static GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
76  {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
77  {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
78  {1, 2} };
79 static GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
80  {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
81  {13, 9}, {11, 11}, {9, 11} };
82 static GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
83  {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
84 static GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
85  {9.6, 15.25}, {9, 15.25} };
86 static GLfloat lightPosition[4];
87 static GLfloat lightColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
88 static GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
89 /* *INDENT-ON* */
90 
91 /* Nice floor texture tiling pattern. */
92 static char *circles[] = {
93  "....xxxx........",
94  "..xxxxxxxx......",
95  ".xxxxxxxxxx.....",
96  ".xxx....xxx.....",
97  "xxx......xxx....",
98  "xxx......xxx....",
99  "xxx......xxx....",
100  "xxx......xxx....",
101  ".xxx....xxx.....",
102  ".xxxxxxxxxx.....",
103  "..xxxxxxxx......",
104  "....xxxx........",
105  "................",
106  "................",
107  "................",
108  "................",
109 };
110 
111 static void
113 {
114  GLubyte floorTexture[16][16][3];
115  GLubyte *loc;
116  int s, t;
117 
118  /* Setup RGB image for the texture. */
119  loc = (GLubyte*) floorTexture;
120  for (t = 0; t < 16; t++) {
121  for (s = 0; s < 16; s++) {
122  if (circles[t][s] == 'x') {
123  /* Nice green. */
124  loc[0] = 0x1f;
125  loc[1] = 0x8f;
126  loc[2] = 0x1f;
127  } else {
128  /* Light gray. */
129  loc[0] = 0xaa;
130  loc[1] = 0xaa;
131  loc[2] = 0xaa;
132  }
133  loc += 3;
134  }
135  }
136 
137  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
138 
139  if (useMipmaps) {
140  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
141  GL_LINEAR_MIPMAP_LINEAR);
142  gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
143  GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
144  } else {
145  if (linearFiltering) {
146  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147  } else {
148  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
149  }
150  glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
151  GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
152  }
153 }
154 
155 enum {
156  X, Y, Z, W
157 };
158 enum {
159  A, B, C, D
160 };
161 
162 /* Create a matrix that will project the desired shadow. */
163 void
164 shadowMatrix(GLfloat shadowMat[4][4],
165  GLfloat groundplane[4],
166  GLfloat lightpos[4])
167 {
168  GLfloat dot;
169 
170  /* Find dot product between light position vector and ground plane normal. */
171  dot = groundplane[X] * lightpos[X] +
172  groundplane[Y] * lightpos[Y] +
173  groundplane[Z] * lightpos[Z] +
174  groundplane[W] * lightpos[W];
175 
176  shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
177  shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
178  shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
179  shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
180 
181  shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
182  shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
183  shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
184  shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
185 
186  shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
187  shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
188  shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
189  shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
190 
191  shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
192  shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
193  shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
194  shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
195 
196 }
197 
198 /* Find the plane equation given 3 points. */
199 void
200 findPlane(GLfloat plane[4],
201  GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
202 {
203  GLfloat vec0[3], vec1[3];
204 
205  /* Need 2 vectors to find cross product. */
206  vec0[X] = v1[X] - v0[X];
207  vec0[Y] = v1[Y] - v0[Y];
208  vec0[Z] = v1[Z] - v0[Z];
209 
210  vec1[X] = v2[X] - v0[X];
211  vec1[Y] = v2[Y] - v0[Y];
212  vec1[Z] = v2[Z] - v0[Z];
213 
214  /* find cross product to get A, B, and C of plane equation */
215  plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
216  plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
217  plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
218 
219  plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
220 }
221 
222 void
223 extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
224  GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
225 {
226  static GLUtriangulatorObj *tobj = NULL;
227  GLdouble vertex[3], dx, dy, len;
228  int i;
229  int count = (int) (dataSize / (2 * sizeof(GLfloat)));
230 
231  if (tobj == NULL) {
232  tobj = gluNewTess(); /* create and initialize a GLU
233  polygon tesselation object */
234  gluTessCallback(tobj, GLU_BEGIN, glBegin);
235  gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky */
236  gluTessCallback(tobj, GLU_END, glEnd);
237  }
238  glNewList(side, GL_COMPILE);
239  glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
240  tessellation */
241  gluBeginPolygon(tobj);
242  for (i = 0; i < count; i++) {
243  vertex[0] = data[i][0];
244  vertex[1] = data[i][1];
245  vertex[2] = 0;
246  gluTessVertex(tobj, vertex, data[i]);
247  }
248  gluEndPolygon(tobj);
249  glEndList();
250  glNewList(edge, GL_COMPILE);
251  glShadeModel(GL_FLAT); /* flat shade keeps angular hands
252  from being "smoothed" */
253  glBegin(GL_QUAD_STRIP);
254  for (i = 0; i <= count; i++) {
255  /* mod function handles closing the edge */
256  glVertex3f(data[i % count][0], data[i % count][1], 0.0);
257  glVertex3f(data[i % count][0], data[i % count][1], thickness);
258  /* Calculate a unit normal by dividing by Euclidean
259  distance. We * could be lazy and use
260  glEnable(GL_NORMALIZE) so we could pass in * arbitrary
261  normals for a very slight performance hit. */
262  dx = data[(i + 1) % count][1] - data[i % count][1];
263  dy = data[i % count][0] - data[(i + 1) % count][0];
264  len = sqrt(dx * dx + dy * dy);
265  glNormal3f(dx / len, dy / len, 0.0);
266  }
267  glEnd();
268  glEndList();
269  glNewList(whole, GL_COMPILE);
270  glFrontFace(GL_CW);
271  glCallList(edge);
272  glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
273  glCallList(side);
274  glPushMatrix();
275  glTranslatef(0.0, 0.0, thickness);
276  glFrontFace(GL_CCW);
277  glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
278  glCallList(side);
279  glPopMatrix();
280  glEndList();
281 }
282 
283 /* Enumerants for refering to display lists. */
284 typedef enum {
287 } displayLists;
288 
289 static void
291 {
298  extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
300 }
301 
302 static void
304 
305 {
306  glPushMatrix();
307  /* Translate the dinosaur to be at (0,8,0). */
308  glTranslatef(-8, 0, -bodyWidth / 2);
309  glTranslatef(0.0, jump, 0.0);
310  glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
311  glCallList(BODY_WHOLE);
312  glTranslatef(0.0, 0.0, bodyWidth);
313  glCallList(ARM_WHOLE);
314  glCallList(LEG_WHOLE);
315  glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
316  glCallList(ARM_WHOLE);
317  glTranslatef(0.0, 0.0, -bodyWidth / 4);
318  glCallList(LEG_WHOLE);
319  glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
320  glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
321  glCallList(EYE_WHOLE);
322  glPopMatrix();
323 }
324 
325 static GLfloat floorVertices[4][3] = {
326  { -20.0, 0.0, 20.0 },
327  { 20.0, 0.0, 20.0 },
328  { 20.0, 0.0, -20.0 },
329  { -20.0, 0.0, -20.0 },
330 };
331 
332 /* Draw a floor (possibly textured). */
333 static void
335 {
336  glDisable(GL_LIGHTING);
337 
338  if (useTexture) {
339  glEnable(GL_TEXTURE_2D);
340  }
341 
342  glBegin(GL_QUADS);
343  glTexCoord2f(0.0, 0.0);
344  glVertex3fv(floorVertices[0]);
345  glTexCoord2f(0.0, 16.0);
346  glVertex3fv(floorVertices[1]);
347  glTexCoord2f(16.0, 16.0);
348  glVertex3fv(floorVertices[2]);
349  glTexCoord2f(16.0, 0.0);
350  glVertex3fv(floorVertices[3]);
351  glEnd();
352 
353  if (useTexture) {
354  glDisable(GL_TEXTURE_2D);
355  }
356 
357  glEnable(GL_LIGHTING);
358 }
359 
360 static GLfloat floorPlane[4];
361 static GLfloat floorShadow[4][4];
362 
363 static void
364 redraw(void)
365 {
366  int start, end;
367 
368  if (reportSpeed) {
369  start = glutGet(GLUT_ELAPSED_TIME);
370  }
371 
372  /* Clear; default stencil clears to zero. */
374  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
375  } else {
376  /* Avoid clearing stencil when not using it. */
377  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
378  }
379 
380  /* Reposition the light source. */
381  lightPosition[0] = 12*cos(lightAngle);
383  lightPosition[2] = 12*sin(lightAngle);
384  if (directionalLight) {
385  lightPosition[3] = 0.0;
386  } else {
387  lightPosition[3] = 1.0;
388  }
389 
391 
392  glPushMatrix();
393  /* Perform scene rotations based on user mouse input. */
394  glRotatef(angle2, 1.0, 0.0, 0.0);
395  glRotatef(angle, 0.0, 1.0, 0.0);
396 
397  /* Tell GL new light source position. */
398  glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
399 
400  if (renderReflection) {
401  if (stencilReflection) {
402  /* We can eliminate the visual "artifact" of seeing the "flipped"
403  dinosaur underneath the floor by using stencil. The idea is
404  draw the floor without color or depth update but so that
405  a stencil value of one is where the floor will be. Later when
406  rendering the dinosaur reflection, we will only update pixels
407  with a stencil value of 1 to make sure the reflection only
408  lives on the floor, not below the floor. */
409 
410  /* Don't update color or depth. */
411  glDisable(GL_DEPTH_TEST);
412  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
413 
414  /* Draw 1 into the stencil buffer. */
415  glEnable(GL_STENCIL_TEST);
416  glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
417  glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
418 
419  /* Now render floor; floor pixels just get their stencil set to 1. */
420  drawFloor();
421 
422  /* Re-enable update of color and depth. */
423  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
424  glEnable(GL_DEPTH_TEST);
425 
426  /* Now, only render where stencil is set to 1. */
427  glStencilFunc(GL_EQUAL, 1, 0xffffffff); /* draw if ==1 */
428  glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
429  }
430 
431  glPushMatrix();
432 
433  /* The critical reflection step: Reflect dinosaur through the floor
434  (the Y=0 plane) to make a relection. */
435  glScalef(1.0, -1.0, 1.0);
436 
437  /* Reflect the light position. */
438  glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
439 
440  /* To avoid our normals getting reversed and hence botched lighting
441  on the reflection, turn on normalize. */
442  glEnable(GL_NORMALIZE);
443  glCullFace(GL_FRONT);
444 
445  /* Draw the reflected dinosaur. */
446  drawDinosaur();
447 
448  /* Disable noramlize again and re-enable back face culling. */
449  glDisable(GL_NORMALIZE);
450  glCullFace(GL_BACK);
451 
452  glPopMatrix();
453 
454  /* Switch back to the unreflected light position. */
455  glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
456 
457  if (stencilReflection) {
458  glDisable(GL_STENCIL_TEST);
459  }
460  }
461 
462  /* Back face culling will get used to only draw either the top or the
463  bottom floor. This let's us get a floor with two distinct
464  appearances. The top floor surface is reflective and kind of red.
465  The bottom floor surface is not reflective and blue. */
466 
467  /* Draw "bottom" of floor in blue. */
468  glFrontFace(GL_CW); /* Switch face orientation. */
469  glColor4f(0.1, 0.1, 0.7, 1.0);
470  drawFloor();
471  glFrontFace(GL_CCW);
472 
473  if (renderShadow) {
474  if (stencilShadow) {
475  /* Draw the floor with stencil value 3. This helps us only
476  draw the shadow once per floor pixel (and only on the
477  floor pixels). */
478  glEnable(GL_STENCIL_TEST);
479  glStencilFunc(GL_ALWAYS, 3, 0xffffffff);
480  glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
481  }
482  }
483 
484  /* Draw "top" of floor. Use blending to blend in reflection. */
485  glEnable(GL_BLEND);
486  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
487  glColor4f(0.7, 0.0, 0.0, 0.3);
488  glColor4f(1.0, 1.0, 1.0, 0.3);
489  drawFloor();
490  glDisable(GL_BLEND);
491 
492  if (renderDinosaur) {
493  /* Draw "actual" dinosaur, not its reflection. */
494  drawDinosaur();
495  }
496 
497  if (renderShadow) {
498 
499  /* Render the projected shadow. */
500 
501  if (stencilShadow) {
502 
503  /* Now, only render where stencil is set above 2 (ie, 3 where
504  the top floor is). Update stencil with 2 where the shadow
505  gets drawn so we don't redraw (and accidently reblend) the
506  shadow). */
507  glStencilFunc(GL_LESS, 2, 0xffffffff); /* draw if ==1 */
508  glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
509  }
510 
511  /* To eliminate depth buffer artifacts, we use polygon offset
512  to raise the depth of the projected shadow slightly so
513  that it does not depth buffer alias with the floor. */
514  if (offsetShadow) {
515  switch (polygonOffsetVersion) {
516  case EXTENSION:
517 #ifdef GL_EXT_polygon_offset
518  glEnable(GL_POLYGON_OFFSET_EXT);
519  break;
520 #endif
521 #ifdef GL_VERSION_1_1
522  case ONE_DOT_ONE:
523  glEnable(GL_POLYGON_OFFSET_FILL);
524  break;
525 #endif
526  case MISSING:
527  /* Oh well. */
528  break;
529  }
530  }
531 
532  /* Render 50% black shadow color on top of whatever the
533  floor appareance is. */
534  glEnable(GL_BLEND);
535  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
536  glDisable(GL_LIGHTING); /* Force the 50% black. */
537  glColor4f(0.0, 0.0, 0.0, 0.5);
538 
539  glPushMatrix();
540  /* Project the shadow. */
541  glMultMatrixf((GLfloat *) floorShadow);
542  drawDinosaur();
543  glPopMatrix();
544 
545  glDisable(GL_BLEND);
546  glEnable(GL_LIGHTING);
547 
548  if (offsetShadow) {
549  switch (polygonOffsetVersion) {
550 #ifdef GL_EXT_polygon_offset
551  case EXTENSION:
552  glDisable(GL_POLYGON_OFFSET_EXT);
553  break;
554 #endif
555 #ifdef GL_VERSION_1_1
556  case ONE_DOT_ONE:
557  glDisable(GL_POLYGON_OFFSET_FILL);
558  break;
559 #endif
560  case MISSING:
561  /* Oh well. */
562  break;
563  }
564  }
565  if (stencilShadow) {
566  glDisable(GL_STENCIL_TEST);
567  }
568  }
569 
570  glPushMatrix();
571  glDisable(GL_LIGHTING);
572  glColor3f(1.0, 1.0, 0.0);
573  if (directionalLight) {
574  /* Draw an arrowhead. */
575  glDisable(GL_CULL_FACE);
576  glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
577  glRotatef(lightAngle * -180.0 / M_PI, 0, 1, 0);
578  glRotatef(atan(lightHeight/12) * 180.0 / M_PI, 0, 0, 1);
579  glBegin(GL_TRIANGLE_FAN);
580  glVertex3f(0, 0, 0);
581  glVertex3f(2, 1, 1);
582  glVertex3f(2, -1, 1);
583  glVertex3f(2, -1, -1);
584  glVertex3f(2, 1, -1);
585  glVertex3f(2, 1, 1);
586  glEnd();
587  /* Draw a white line from light direction. */
588  glColor3f(1.0, 1.0, 1.0);
589  glBegin(GL_LINES);
590  glVertex3f(0, 0, 0);
591  glVertex3f(5, 0, 0);
592  glEnd();
593  glEnable(GL_CULL_FACE);
594  } else {
595  /* Draw a yellow ball at the light source. */
596  glTranslatef(lightPosition[0], lightPosition[1], lightPosition[2]);
597  glutSolidSphere(1.0, 5, 5);
598  }
599  glEnable(GL_LIGHTING);
600  glPopMatrix();
601 
602  glPopMatrix();
603 
604  if (reportSpeed) {
605  glFinish();
606  end = glutGet(GLUT_ELAPSED_TIME);
607  printf("Speed %.3g frames/sec (%d ms)\n", 1000.0/(end-start), end-start);
608  }
609 
610  glutSwapBuffers();
611 }
612 
613 /* ARGSUSED2 */
614 static void
615 mouse(int button, int state, int x, int y)
616 {
617  if (button == GLUT_LEFT_BUTTON) {
618  if (state == GLUT_DOWN) {
619  moving = 1;
620  startx = x;
621  starty = y;
622  }
623  if (state == GLUT_UP) {
624  moving = 0;
625  }
626  }
627  if (button == GLUT_MIDDLE_BUTTON) {
628  if (state == GLUT_DOWN) {
629  lightMoving = 1;
630  lightStartX = x;
631  lightStartY = y;
632  }
633  if (state == GLUT_UP) {
634  lightMoving = 0;
635  }
636  }
637 }
638 
639 /* ARGSUSED1 */
640 static void
641 motion(int x, int y)
642 {
643  if (moving) {
644  angle = angle + (x - startx);
645  angle2 = angle2 + (y - starty);
646  startx = x;
647  starty = y;
648  glutPostRedisplay();
649  }
650  if (lightMoving) {
651  lightAngle += (x - lightStartX)/40.0;
652  lightHeight += (lightStartY - y)/20.0;
653  lightStartX = x;
654  lightStartY = y;
655  glutPostRedisplay();
656  }
657 }
658 
659 /* Advance time varying state when idle callback registered. */
660 static void
661 idle(void)
662 {
663  static float time = 0.0;
664 
665  time = glutGet(GLUT_ELAPSED_TIME) / 500.0;
666 
667  jump = 4.0 * fabs(sin(time)*0.5);
668  if (!lightMoving) {
669  lightAngle += 0.03;
670  }
671  glutPostRedisplay();
672 }
673 
674 enum {
678 };
679 
680 static void
681 controlLights(int value)
682 {
683  switch (value) {
684  case M_NONE:
685  return;
686  case M_MOTION:
687  animation = 1 - animation;
688  if (animation) {
689  glutIdleFunc(idle);
690  } else {
691  glutIdleFunc(NULL);
692  }
693  break;
694  case M_LIGHT:
696  if (lightSwitch) {
697  glEnable(GL_LIGHT0);
698  } else {
699  glDisable(GL_LIGHT0);
700  }
701  break;
702  case M_TEXTURE:
704  break;
705  case M_SHADOWS:
707  break;
708  case M_REFLECTION:
710  break;
711  case M_DINOSAUR:
713  break;
716  break;
717  case M_STENCIL_SHADOW:
719  break;
720  case M_OFFSET_SHADOW:
722  break;
723  case M_POSITIONAL:
724  directionalLight = 0;
725  break;
726  case M_DIRECTIONAL:
727  directionalLight = 1;
728  break;
729  case M_PERFORMANCE:
730  reportSpeed = 1 - reportSpeed;
731  break;
732  }
733  glutPostRedisplay();
734 }
735 
736 /* When not visible, stop animating. Restart when visible again. */
737 static void
738 visible(int vis)
739 {
740  if (vis == GLUT_VISIBLE) {
741  if (animation)
742  glutIdleFunc(idle);
743  } else {
744  if (!animation)
745  glutIdleFunc(NULL);
746  }
747 }
748 
749 /* Press any key to redraw; good when motion stopped and
750  performance reporting on. */
751 /* ARGSUSED */
752 static void
753 key(unsigned char c, int x, int y)
754 {
755  if (c == 27) {
756  exit(0); /* IRIS GLism, Escape quits. */
757  }
758  glutPostRedisplay();
759 }
760 
761 /* Press any key to redraw; good when motion stopped and
762  performance reporting on. */
763 /* ARGSUSED */
764 static void
765 special(int k, int x, int y)
766 {
767  glutPostRedisplay();
768 }
769 
770 static int
772 {
773  const char *version;
774  int major, minor;
775 
776  version = (char *) glGetString(GL_VERSION);
777  if (sscanf(version, "%d.%d", &major, &minor) == 2)
778  return major >= 1 && minor >= 1;
779  return 0; /* OpenGL version string malformed! */
780 }
781 
782 int
783 main(int argc, char **argv)
784 {
785  int i;
786 
787  glutInit(&argc, argv);
788 
789  for (i=1; i<argc; i++) {
790  if (!strcmp("-linear", argv[i])) {
791  linearFiltering = 1;
792  } else if (!strcmp("-mipmap", argv[i])) {
793  useMipmaps = 1;
794  } else if (!strcmp("-ext", argv[i])) {
795  forceExtension = 1;
796  }
797  }
798 
799  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL | GLUT_MULTISAMPLE);
800 
801 #if 1
802  /* In GLUT 4.0, you'll be able to do this an be sure to
803  get 2 bits of stencil if the machine has it for you. */
804  glutInitDisplayString("samples stencil>=2 rgb double depth");
805 #endif
806 
807  glutCreateWindow("Shadowy Leapin' Lizards");
808 
809  if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {
810  printf("dinoshade: Sorry, I need at least 2 bits of stencil.\n");
811  exit(1);
812  }
813 
814  /* Register GLUT callbacks. */
815  glutDisplayFunc(redraw);
816  glutMouseFunc(mouse);
817  glutMotionFunc(motion);
818  glutVisibilityFunc(visible);
819  glutKeyboardFunc(key);
820  glutSpecialFunc(special);
821 
822  glutCreateMenu(controlLights);
823 
824  glutAddMenuEntry("Toggle motion", M_MOTION);
825  glutAddMenuEntry("-----------------------", M_NONE);
826  glutAddMenuEntry("Toggle light", M_LIGHT);
827  glutAddMenuEntry("Toggle texture", M_TEXTURE);
828  glutAddMenuEntry("Toggle shadows", M_SHADOWS);
829  glutAddMenuEntry("Toggle reflection", M_REFLECTION);
830  glutAddMenuEntry("Toggle dinosaur", M_DINOSAUR);
831  glutAddMenuEntry("-----------------------", M_NONE);
832  glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);
833  glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);
834  glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);
835  glutAddMenuEntry("----------------------", M_NONE);
836  glutAddMenuEntry("Positional light", M_POSITIONAL);
837  glutAddMenuEntry("Directional light", M_DIRECTIONAL);
838  glutAddMenuEntry("-----------------------", M_NONE);
839  glutAddMenuEntry("Toggle performance", M_PERFORMANCE);
840  glutAttachMenu(GLUT_RIGHT_BUTTON);
841  makeDinosaur();
842 
843 #ifdef GL_VERSION_1_1
844  if (supportsOneDotOne() && !forceExtension) {
846  glPolygonOffset(-2.0, -1.0);
847  } else
848 #endif
849  {
850 #ifdef GL_EXT_polygon_offset
851  /* check for the polygon offset extension */
852  if (glutExtensionSupported("GL_EXT_polygon_offset")) {
854  glPolygonOffsetEXT(-0.1, -0.002);
855  } else
856 #endif
857  {
859  printf("\ndinoshine: Missing polygon offset.\n");
860  printf(" Expect shadow depth aliasing artifacts.\n\n");
861  }
862  }
863 
864  glEnable(GL_CULL_FACE);
865  glEnable(GL_DEPTH_TEST);
866  glEnable(GL_TEXTURE_2D);
867  glLineWidth(3.0);
868 
869  glMatrixMode(GL_PROJECTION);
870  gluPerspective( /* field of view in degree */ 40.0,
871  /* aspect ratio */ 1.0,
872  /* Z near */ 20.0, /* Z far */ 100.0);
873  glMatrixMode(GL_MODELVIEW);
874  gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,8,60) */
875  0.0, 8.0, 0.0, /* center is at (0,8,0) */
876  0.0, 1.0, 0.); /* up is in postivie Y direction */
877 
878  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
879  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
880  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
881  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
882  glEnable(GL_LIGHT0);
883  glEnable(GL_LIGHTING);
884 
886 
887  /* Setup floor plane for projected shadow calculations. */
889 
890  glutMainLoop();
891  return 0; /* ANSI C requires main to return int. */
892 }
static void drawFloor(void)
Definition: dinoshade.c:334
static float jump
Definition: dinoshade.c:60
int main(int argc, char **argv)
Definition: dinoshade.c:783
Definition: eustags.c:162
double cos()
double sin()
static void makeDinosaur(void)
Definition: dinoshade.c:290
int starty
Definition: dinoshade.c:65
static float lightHeight
Definition: dinoshade.c:61
static GLfloat floorShadow[4][4]
Definition: dinoshade.c:361
static void drawDinosaur(void)
Definition: dinoshade.c:303
static GLfloat body[][2]
Definition: dinoshade.c:75
static GLfloat lightColor[]
Definition: dinoshade.c:87
static int directionalLight
Definition: dinoshade.c:56
static GLfloat lightPosition[4]
Definition: dinoshade.c:86
static int argc
Definition: transargv.c:56
static void controlLights(int value)
Definition: dinoshade.c:681
static void visible(int vis)
Definition: dinoshade.c:738
GLfloat angle2
Definition: dinoshade.c:63
static void special(int k, int x, int y)
Definition: dinoshade.c:765
static GLfloat leg[][2]
Definition: dinoshade.c:82
static GLfloat floorVertices[4][3]
Definition: dinoshade.c:325
static int renderReflection
Definition: dinoshade.c:51
static GLdouble bodyWidth
Definition: dinoshade.c:73
static int useMipmaps
Definition: dinoshade.c:52
static char * circles[]
Definition: dinoshade.c:92
int moving
Definition: dinoshade.c:65
Definition: dinoshade.c:159
static void key(unsigned char c, int x, int y)
Definition: dinoshade.c:753
string version
Definition: latex/conf.py:66
void extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize, GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
Definition: dinoshade.c:223
static int linearFiltering
Definition: dinoshade.c:52
static void makeFloorTexture(void)
Definition: dinoshade.c:112
GLfloat angle
Definition: dinoshade.c:62
#define M_PI
Definition: dinoshade.c:46
void findPlane(GLfloat plane[4], GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
Definition: dinoshade.c:200
double sqrt()
static int supportsOneDotOne(void)
Definition: dinoshade.c:771
static GLfloat floorPlane[4]
Definition: dinoshade.c:360
static void motion(int x, int y)
Definition: dinoshade.c:641
Definition: dinoshade.c:156
short s
Definition: structsize.c:2
static time_stamp_t start
Definition: rgc_utils.c:75
int lightStartX
Definition: dinoshade.c:66
static int renderDinosaur
Definition: dinoshade.c:51
displayLists
Definition: dinoshade.c:284
Definition: dinoshade.c:159
int lightMoving
Definition: dinoshade.c:66
static GLboolean lightSwitch
Definition: dinoshade.c:55
Definition: dinoshade.c:159
void shadowMatrix(GLfloat shadowMat[4][4], GLfloat groundplane[4], GLfloat lightpos[4])
Definition: dinoshade.c:164
Definition: dinoshade.c:156
int count
Definition: thrtest.c:11
Definition: dinoshade.c:159
#define NULL
Definition: transargv.c:8
static GLfloat eyeColor[]
Definition: dinoshade.c:88
Definition: dinoshade.c:156
static void mouse(int button, int state, int x, int y)
Definition: dinoshade.c:615
static GLfloat eye[][2]
Definition: dinoshade.c:84
Definition: dinoshade.c:156
static int stencilReflection
Definition: dinoshade.c:50
static int stencilShadow
Definition: dinoshade.c:50
int startx
Definition: dinoshade.c:65
static int reportSpeed
Definition: dinoshade.c:53
static void redraw(void)
Definition: dinoshade.c:364
static float lightAngle
Definition: dinoshade.c:61
int polygonOffsetVersion
Definition: dinoshade.c:71
static int renderShadow
Definition: dinoshade.c:51
int lightStartY
Definition: dinoshade.c:66
static GLfloat skinColor[]
Definition: dinoshade.c:88
static int animation
Definition: dinoshade.c:54
static int useTexture
Definition: dinoshade.c:52
static void idle(void)
Definition: dinoshade.c:661
static GLfloat arm[][2]
Definition: dinoshade.c:79
edge(MATRIX f, int n, unsigned int planetab, unsigned int planework, int r, linetab, int m)
Definition: edge.c:5
static int offsetShadow
Definition: dinoshade.c:50
static int forceExtension
Definition: dinoshade.c:57


euslisp
Author(s): Toshihiro Matsui
autogenerated on Mon Feb 28 2022 22:18:27