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