1 /*************************************************************************
2  *                                                                       *
3  * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith.       *
4  * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
5  *                                                                       *
6  * This library is free software; you can redistribute it and/or         *
7  * modify it under the terms of EITHER:                                  *
8  *   (1) The GNU Lesser General Public License as published by the Free  *
9  *       Software Foundation; either version 2.1 of the License, or (at  *
10  *       your option) any later version. The text of the GNU Lesser      *
11  *       General Public License is included with this library in the     *
12  *       file LICENSE.TXT.                                               *
13  *   (2) The BSD-style license that is included with this library in     *
14  *       the file LICENSE-BSD.TXT.                                       *
15  *                                                                       *
16  * This library is distributed in the hope that it will be useful,       *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
19  * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
20  *                                                                       *
21  *************************************************************************/
22 
23 /*
24 
25 simple graphics.
26 
27 the following command line flags can be used (typically under unix)
28   -notex              Do not use any textures
29   -noshadow[s]        Do not draw any shadows
30   -pause              Start the simulation paused
31   -texturepath <path> Inform an alternative textures path
32 
33 TODO
34 ----
35 
36 manage openGL state changes better
37 
38 */
39 
40 #ifdef WIN32
41 #include <windows.h>
42 #endif
43 
44 #include <ode/ode.h>
45 #include "config.h"
46 
47 #ifdef HAVE_APPLE_OPENGL_FRAMEWORK
48 #include <OpenGL/gl.h>
49 #include <OpenGL/glu.h>
50 #else
51 #include <GL/gl.h>
52 #include <GL/glu.h>
53 #endif
54 
55 #include "drawstuff/drawstuff.h"
56 #include "internal.h"
57 
58 //***************************************************************************
59 // misc
60 
61 #ifndef DEFAULT_PATH_TO_TEXTURES
62 #if 0
63 #define DEFAULT_PATH_TO_TEXTURES "..\\textures\\"
64 #else
65 #define DEFAULT_PATH_TO_TEXTURES "../textures/"
66 #endif
67 #endif
68 
69 #ifndef M_PI
70 #define M_PI (3.14159265358979323846)
71 #endif
72 
73 // constants to convert degrees to radians and the reverse
74 #define RAD_TO_DEG (180.0/M_PI)
75 #define DEG_TO_RAD (M_PI/180.0)
76 
77 // light vector. LIGHTZ is implicitly 1
78 #define LIGHTX (1.0f)
79 #define LIGHTY (0.4f)
80 
81 // ground and sky
82 #define SHADOW_INTENSITY (0.65f)
83 #define GROUND_R (0.5f) 	// ground color for when there's no texture
84 #define GROUND_G (0.5f)
85 #define GROUND_B (0.3f)
86 
87 const float ground_scale = 1.0f/1.0f;	// ground texture scale (1/size)
88 const float ground_ofsx = 0.5;		// offset of ground texture
89 const float ground_ofsy = 0.5;
90 const float sky_scale = 1.0f/4.0f;	// sky texture scale (1/size)
91 const float sky_height = 1.0f;		// sky height above viewpoint
92 
93 //***************************************************************************
94 // misc mathematics stuff
95 
normalizeVector3(float v[3])96 static void normalizeVector3 (float v[3])
97 {
98   float len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
99   if (len <= 0.0f) {
100     v[0] = 1;
101     v[1] = 0;
102     v[2] = 0;
103   }
104   else {
105     len = 1.0f / (float)sqrt(len);
106     v[0] *= len;
107     v[1] *= len;
108     v[2] *= len;
109   }
110 }
111 
crossProduct3(float res[3],const float a[3],const float b[3])112 static void crossProduct3(float res[3], const float a[3], const float b[3])
113 {
114   float res_0 = a[1]*b[2] - a[2]*b[1];
115   float res_1 = a[2]*b[0] - a[0]*b[2];
116   float res_2 = a[0]*b[1] - a[1]*b[0];
117   // Only assign after all the calculations are over to avoid incurring memory aliasing
118   res[0] = res_0;
119   res[1] = res_1;
120   res[2] = res_2;
121 }
122 
123 //***************************************************************************
124 // PPM image object
125 
126 typedef unsigned char byte;
127 
128 class Image {
129   int image_width,image_height;
130   byte *image_data;
131 public:
132   Image (char *filename);
133   // load from PPM file
134   ~Image();
width()135   int width() { return image_width; }
height()136   int height() { return image_height; }
data()137   byte *data() { return image_data; }
138 };
139 
140 
141 // skip over whitespace and comments in a stream.
142 
skipWhiteSpace(char * filename,FILE * f)143 static void skipWhiteSpace (char *filename, FILE *f)
144 {
145   int c,d;
146   for(;;) {
147     c = fgetc(f);
148     if (c==EOF) dsError ("unexpected end of file in \"%s\"",filename);
149 
150     // skip comments
151     if (c == '#') {
152       do {
153 	d = fgetc(f);
154 	if (d==EOF) dsError ("unexpected end of file in \"%s\"",filename);
155       } while (d != '\n');
156       continue;
157     }
158 
159     if (c > ' ') {
160       ungetc (c,f);
161       return;
162     }
163   }
164 }
165 
166 
167 // read a number from a stream, this return 0 if there is none (that's okay
168 // because 0 is a bad value for all PPM numbers anyway).
169 
readNumber(char * filename,FILE * f)170 static int readNumber (char *filename, FILE *f)
171 {
172   int c,n=0;
173   for(;;) {
174     c = fgetc(f);
175     if (c==EOF) dsError ("unexpected end of file in \"%s\"",filename);
176     if (c >= '0' && c <= '9') n = n*10 + (c - '0');
177     else {
178       ungetc (c,f);
179       return n;
180     }
181   }
182 }
183 
184 
Image(char * filename)185 Image::Image (char *filename)
186 {
187   FILE *f = fopen (filename,"rb");
188   if (!f) dsError ("Can't open image file `%s'",filename);
189 
190   // read in header
191   if (fgetc(f) != 'P' || fgetc(f) != '6')
192     dsError ("image file \"%s\" is not a binary PPM (no P6 header)",filename);
193   skipWhiteSpace (filename,f);
194 
195   // read in image parameters
196   image_width = readNumber (filename,f);
197   skipWhiteSpace (filename,f);
198   image_height = readNumber (filename,f);
199   skipWhiteSpace (filename,f);
200   int max_value = readNumber (filename,f);
201 
202   // check values
203   if (image_width < 1 || image_height < 1)
204     dsError ("bad image file \"%s\"",filename);
205   if (max_value != 255)
206     dsError ("image file \"%s\" must have color range of 255",filename);
207 
208   // read either nothing, LF (10), or CR,LF (13,10)
209   int c = fgetc(f);
210   if (c == 10) {
211     // LF
212   }
213   else if (c == 13) {
214     // CR
215     c = fgetc(f);
216     if (c != 10) ungetc (c,f);
217   }
218   else ungetc (c,f);
219 
220   // read in rest of data
221   image_data = new byte [image_width*image_height*3];
222   if (fread (image_data,image_width*image_height*3,1,f) != 1)
223     dsError ("Can not read data from image file `%s'",filename);
224   fclose (f);
225 }
226 
227 
~Image()228 Image::~Image()
229 {
230   delete[] image_data;
231 }
232 
233 //***************************************************************************
234 // Texture object.
235 
236 class Texture {
237   Image *image;
238   GLuint name;
239 public:
240   Texture (char *filename);
241   ~Texture();
242   void bind (int modulate);
243 };
244 
245 
Texture(char * filename)246 Texture::Texture (char *filename)
247 {
248   image = new Image (filename);
249   glGenTextures (1,&name);
250   glBindTexture (GL_TEXTURE_2D,name);
251 
252   // set pixel unpacking mode
253   glPixelStorei (GL_UNPACK_SWAP_BYTES, 0);
254   glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
255   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
256   glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
257   glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
258 
259   // glTexImage2D (GL_TEXTURE_2D, 0, 3, image->width(), image->height(), 0,
260   //		   GL_RGB, GL_UNSIGNED_BYTE, image->data());
261   gluBuild2DMipmaps (GL_TEXTURE_2D, 3, image->width(), image->height(),
262 		     GL_RGB, GL_UNSIGNED_BYTE, image->data());
263 
264   // set texture parameters - will these also be bound to the texture???
265   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
266   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
267 
268   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
269   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
270 		   GL_LINEAR_MIPMAP_LINEAR);
271 
272   glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
273 }
274 
275 
~Texture()276 Texture::~Texture()
277 {
278   delete image;
279   glDeleteTextures (1,&name);
280 }
281 
282 
bind(int modulate)283 void Texture::bind (int modulate)
284 {
285   glBindTexture (GL_TEXTURE_2D,name);
286   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
287 	     modulate ? GL_MODULATE : GL_DECAL);
288 }
289 
290 //***************************************************************************
291 // the current drawing state (for when the user's step function is drawing)
292 
293 static float color[4] = {0,0,0,0};	// current r,g,b,alpha color
294 static int tnum = 0;			// current texture number
295 
296 //***************************************************************************
297 // OpenGL utility stuff
298 
setCamera(float x,float y,float z,float h,float p,float r)299 static void setCamera (float x, float y, float z, float h, float p, float r)
300 {
301   glMatrixMode (GL_MODELVIEW);
302   glLoadIdentity();
303   glRotatef (90, 0,0,1);
304   glRotatef (90, 0,1,0);
305   glRotatef (r, 1,0,0);
306   glRotatef (p, 0,1,0);
307   glRotatef (-h, 0,0,1);
308   glTranslatef (-x,-y,-z);
309 }
310 
311 
312 // sets the material color, not the light color
313 
setColor(float r,float g,float b,float alpha)314 static void setColor (float r, float g, float b, float alpha)
315 {
316   GLfloat light_ambient[4],light_diffuse[4],light_specular[4];
317   light_ambient[0] = r*0.3f;
318   light_ambient[1] = g*0.3f;
319   light_ambient[2] = b*0.3f;
320   light_ambient[3] = alpha;
321   light_diffuse[0] = r*0.7f;
322   light_diffuse[1] = g*0.7f;
323   light_diffuse[2] = b*0.7f;
324   light_diffuse[3] = alpha;
325   light_specular[0] = r*0.2f;
326   light_specular[1] = g*0.2f;
327   light_specular[2] = b*0.2f;
328   light_specular[3] = alpha;
329   glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, light_ambient);
330   glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, light_diffuse);
331   glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, light_specular);
332   glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 5.0f);
333 }
334 
335 
setTransform(const float pos[3],const float R[12])336 static void setTransform (const float pos[3], const float R[12])
337 {
338   GLfloat matrix[16];
339   matrix[0]=R[0];
340   matrix[1]=R[4];
341   matrix[2]=R[8];
342   matrix[3]=0;
343   matrix[4]=R[1];
344   matrix[5]=R[5];
345   matrix[6]=R[9];
346   matrix[7]=0;
347   matrix[8]=R[2];
348   matrix[9]=R[6];
349   matrix[10]=R[10];
350   matrix[11]=0;
351   matrix[12]=pos[0];
352   matrix[13]=pos[1];
353   matrix[14]=pos[2];
354   matrix[15]=1;
355   glPushMatrix();
356   glMultMatrixf (matrix);
357 }
setTransformD(const double pos[3],const double R[12])358 static void setTransformD (const double pos[3], const double R[12])
359 {
360   GLdouble matrix[16];
361   matrix[0]=R[0];
362   matrix[1]=R[4];
363   matrix[2]=R[8];
364   matrix[3]=0;
365   matrix[4]=R[1];
366   matrix[5]=R[5];
367   matrix[6]=R[9];
368   matrix[7]=0;
369   matrix[8]=R[2];
370   matrix[9]=R[6];
371   matrix[10]=R[10];
372   matrix[11]=0;
373   matrix[12]=pos[0];
374   matrix[13]=pos[1];
375   matrix[14]=pos[2];
376   matrix[15]=1;
377   glPushMatrix();
378   glMultMatrixd (matrix);
379 }
380 
381 
382 // set shadow projection transform
383 
setShadowTransform()384 static void setShadowTransform()
385 {
386   GLfloat matrix[16];
387   for (int i=0; i<16; i++) matrix[i] = 0;
388   matrix[0]=1;
389   matrix[5]=1;
390   matrix[8]=-LIGHTX;
391   matrix[9]=-LIGHTY;
392   matrix[15]=1;
393   glPushMatrix();
394   glMultMatrixf (matrix);
395 }
396 
drawConvex(float * _planes,unsigned int _planecount,float * _points,unsigned int _pointcount,unsigned int * _polygons)397 static void drawConvex (float *_planes,unsigned int _planecount,
398 			float *_points,
399 			unsigned int _pointcount,
400 			unsigned int *_polygons)
401 {
402   unsigned int polyindex=0;
403   for(unsigned int i=0;i<_planecount;++i)
404     {
405       unsigned int pointcount=_polygons[polyindex];
406       polyindex++;
407       glBegin (GL_POLYGON);
408        glNormal3f(_planes[(i*4)+0],
409 		  _planes[(i*4)+1],
410 		  _planes[(i*4)+2]);
411       for(unsigned int j=0;j<pointcount;++j)
412 	{
413 	  glVertex3f(_points[_polygons[polyindex]*3],
414 		     _points[(_polygons[polyindex]*3)+1],
415 		     _points[(_polygons[polyindex]*3)+2]);
416 	  polyindex++;
417 	}
418       glEnd();
419     }
420 }
421 
drawConvexD(double * _planes,unsigned int _planecount,double * _points,unsigned int _pointcount,unsigned int * _polygons)422 static void drawConvexD (double *_planes,unsigned int _planecount,
423 			 double *_points,
424 			 unsigned int _pointcount,
425 			 unsigned int *_polygons)
426 {
427   unsigned int polyindex=0;
428   for(unsigned int i=0;i<_planecount;++i)
429     {
430       unsigned int pointcount=_polygons[polyindex];
431       polyindex++;
432       glBegin (GL_POLYGON);
433       glNormal3d(_planes[(i*4)+0],
434 		 _planes[(i*4)+1],
435 		 _planes[(i*4)+2]);
436       for(unsigned int j=0;j<pointcount;++j)
437 	{
438 	  glVertex3d(_points[_polygons[polyindex]*3],
439 		     _points[(_polygons[polyindex]*3)+1],
440 		     _points[(_polygons[polyindex]*3)+2]);
441 	  polyindex++;
442 	}
443       glEnd();
444     }
445 }
446 
drawBox(const float sides[3])447 static void drawBox (const float sides[3])
448 {
449   float lx = sides[0]*0.5f;
450   float ly = sides[1]*0.5f;
451   float lz = sides[2]*0.5f;
452 
453   // sides
454   glBegin (GL_TRIANGLE_STRIP);
455   glNormal3f (-1,0,0);
456   glVertex3f (-lx,-ly,-lz);
457   glVertex3f (-lx,-ly,lz);
458   glVertex3f (-lx,ly,-lz);
459   glVertex3f (-lx,ly,lz);
460   glNormal3f (0,1,0);
461   glVertex3f (lx,ly,-lz);
462   glVertex3f (lx,ly,lz);
463   glNormal3f (1,0,0);
464   glVertex3f (lx,-ly,-lz);
465   glVertex3f (lx,-ly,lz);
466   glNormal3f (0,-1,0);
467   glVertex3f (-lx,-ly,-lz);
468   glVertex3f (-lx,-ly,lz);
469   glEnd();
470 
471   // top face
472   glBegin (GL_TRIANGLE_FAN);
473   glNormal3f (0,0,1);
474   glVertex3f (-lx,-ly,lz);
475   glVertex3f (lx,-ly,lz);
476   glVertex3f (lx,ly,lz);
477   glVertex3f (-lx,ly,lz);
478   glEnd();
479 
480   // bottom face
481   glBegin (GL_TRIANGLE_FAN);
482   glNormal3f (0,0,-1);
483   glVertex3f (-lx,-ly,-lz);
484   glVertex3f (-lx,ly,-lz);
485   glVertex3f (lx,ly,-lz);
486   glVertex3f (lx,-ly,-lz);
487   glEnd();
488 }
489 
490 
491 // This is recursively subdivides a triangular area (vertices p1,p2,p3) into
492 // smaller triangles, and then draws the triangles. All triangle vertices are
493 // normalized to a distance of 1.0 from the origin (p1,p2,p3 are assumed
494 // to be already normalized). Note this is not super-fast because it draws
495 // triangles rather than triangle strips.
496 
drawPatch(float p1[3],float p2[3],float p3[3],int level)497 static void drawPatch (float p1[3], float p2[3], float p3[3], int level)
498 {
499   int i;
500   if (level > 0) {
501     float q1[3],q2[3],q3[3];		 // sub-vertices
502     for (i=0; i<3; i++) {
503       q1[i] = 0.5f*(p1[i]+p2[i]);
504       q2[i] = 0.5f*(p2[i]+p3[i]);
505       q3[i] = 0.5f*(p3[i]+p1[i]);
506     }
507     float length1 = (float)(1.0/sqrt(q1[0]*q1[0]+q1[1]*q1[1]+q1[2]*q1[2]));
508     float length2 = (float)(1.0/sqrt(q2[0]*q2[0]+q2[1]*q2[1]+q2[2]*q2[2]));
509     float length3 = (float)(1.0/sqrt(q3[0]*q3[0]+q3[1]*q3[1]+q3[2]*q3[2]));
510     for (i=0; i<3; i++) {
511       q1[i] *= length1;
512       q2[i] *= length2;
513       q3[i] *= length3;
514     }
515     drawPatch (p1,q1,q3,level-1);
516     drawPatch (q1,p2,q2,level-1);
517     drawPatch (q1,q2,q3,level-1);
518     drawPatch (q3,q2,p3,level-1);
519   }
520   else {
521     glNormal3f (p1[0],p1[1],p1[2]);
522     glVertex3f (p1[0],p1[1],p1[2]);
523     glNormal3f (p2[0],p2[1],p2[2]);
524     glVertex3f (p2[0],p2[1],p2[2]);
525     glNormal3f (p3[0],p3[1],p3[2]);
526     glVertex3f (p3[0],p3[1],p3[2]);
527   }
528 }
529 
530 
531 // draw a sphere of radius 1
532 
533 static int sphere_quality = 1;
534 
drawSphere()535 static void drawSphere()
536 {
537   // icosahedron data for an icosahedron of radius 1.0
538 # define ICX 0.525731112119133606f
539 # define ICZ 0.850650808352039932f
540   static GLfloat idata[12][3] = {
541     {-ICX, 0, ICZ},
542     {ICX, 0, ICZ},
543     {-ICX, 0, -ICZ},
544     {ICX, 0, -ICZ},
545     {0, ICZ, ICX},
546     {0, ICZ, -ICX},
547     {0, -ICZ, ICX},
548     {0, -ICZ, -ICX},
549     {ICZ, ICX, 0},
550     {-ICZ, ICX, 0},
551     {ICZ, -ICX, 0},
552     {-ICZ, -ICX, 0}
553   };
554 
555   static int index[20][3] = {
556     {0, 4, 1},	  {0, 9, 4},
557     {9, 5, 4},	  {4, 5, 8},
558     {4, 8, 1},	  {8, 10, 1},
559     {8, 3, 10},   {5, 3, 8},
560     {5, 2, 3},	  {2, 7, 3},
561     {7, 10, 3},   {7, 6, 10},
562     {7, 11, 6},   {11, 0, 6},
563     {0, 1, 6},	  {6, 1, 10},
564     {9, 0, 11},   {9, 11, 2},
565     {9, 2, 5},	  {7, 2, 11},
566   };
567 
568   static GLuint listnum = 0;
569   if (listnum==0) {
570     listnum = glGenLists (1);
571     glNewList (listnum,GL_COMPILE);
572     glBegin (GL_TRIANGLES);
573     for (int i=0; i<20; i++) {
574       drawPatch (&idata[index[i][2]][0],&idata[index[i][1]][0],
575 		 &idata[index[i][0]][0],sphere_quality);
576     }
577     glEnd();
578     glEndList();
579   }
580   glCallList (listnum);
581 }
582 
583 
drawSphereShadow(float px,float py,float pz,float radius)584 static void drawSphereShadow (float px, float py, float pz, float radius)
585 {
586   // calculate shadow constants based on light vector
587   static int init=0;
588   static float len2,len1,scale;
589   if (!init) {
590     len2 = LIGHTX*LIGHTX + LIGHTY*LIGHTY;
591     len1 = 1.0f/(float)sqrt(len2);
592     scale = (float) sqrt(len2 + 1);
593     init = 1;
594   }
595 
596   // map sphere center to ground plane based on light vector
597   px -= LIGHTX*pz;
598   py -= LIGHTY*pz;
599 
600   const float kx = 0.96592582628907f;
601   const float ky = 0.25881904510252f;
602   float x=radius, y=0;
603 
604   glBegin (GL_TRIANGLE_FAN);
605   for (int i=0; i<24; i++) {
606     // for all points on circle, scale to elongated rotated shadow and draw
607     float x2 = (LIGHTX*x*scale - LIGHTY*y)*len1 + px;
608     float y2 = (LIGHTY*x*scale + LIGHTX*y)*len1 + py;
609     glTexCoord2f (x2*ground_scale+ground_ofsx,y2*ground_scale+ground_ofsy);
610     glVertex3f (x2,y2,0);
611 
612     // rotate [x,y] vector
613     float xtmp = kx*x - ky*y;
614     y = ky*x + kx*y;
615     x = xtmp;
616   }
617   glEnd();
618 }
619 
620 
drawTriangle(const float * v0,const float * v1,const float * v2,int solid)621 static void drawTriangle (const float *v0, const float *v1, const float *v2, int solid)
622 {
623   float u[3],v[3],normal[3];
624   u[0] = v1[0] - v0[0];
625   u[1] = v1[1] - v0[1];
626   u[2] = v1[2] - v0[2];
627   v[0] = v2[0] - v0[0];
628   v[1] = v2[1] - v0[1];
629   v[2] = v2[2] - v0[2];
630   crossProduct3(normal,u,v);
631   normalizeVector3 (normal);
632 
633   glBegin(solid ? GL_TRIANGLES : GL_LINE_STRIP);
634   glNormal3fv (normal);
635   glVertex3fv (v0);
636   glVertex3fv (v1);
637   glVertex3fv (v2);
638   glEnd();
639 }
640 
drawTriangleD(const double * v0,const double * v1,const double * v2,int solid)641 static void drawTriangleD (const double *v0, const double *v1, const double *v2, int solid)
642 {
643   float u[3],v[3],normal[3];
644   u[0] = float( v1[0] - v0[0] );
645   u[1] = float( v1[1] - v0[1] );
646   u[2] = float( v1[2] - v0[2] );
647   v[0] = float( v2[0] - v0[0] );
648   v[1] = float( v2[1] - v0[1] );
649   v[2] = float( v2[2] - v0[2] );
650   crossProduct3(normal,u,v);
651   normalizeVector3 (normal);
652 
653   glBegin(solid ? GL_TRIANGLES : GL_LINE_STRIP);
654   glNormal3fv (normal);
655   glVertex3dv (v0);
656   glVertex3dv (v1);
657   glVertex3dv (v2);
658   glEnd();
659 }
660 
661 
662 // draw a capped cylinder of length l and radius r, aligned along the x axis
663 
664 static int capped_cylinder_quality = 3;
665 
drawCapsule(float l,float r)666 static void drawCapsule (float l, float r)
667 {
668   int i,j;
669   float tmp,nx,ny,nz,start_nx,start_ny,a,ca,sa;
670   // number of sides to the cylinder (divisible by 4):
671   const int n = capped_cylinder_quality*4;
672 
673   l *= 0.5;
674   a = float(M_PI*2.0)/float(n);
675   sa = (float) sin(a);
676   ca = (float) cos(a);
677 
678   // draw cylinder body
679   ny=1; nz=0;		  // normal vector = (0,ny,nz)
680   glBegin (GL_TRIANGLE_STRIP);
681   for (i=0; i<=n; i++) {
682     glNormal3d (ny,nz,0);
683     glVertex3d (ny*r,nz*r,l);
684     glNormal3d (ny,nz,0);
685     glVertex3d (ny*r,nz*r,-l);
686     // rotate ny,nz
687     tmp = ca*ny - sa*nz;
688     nz = sa*ny + ca*nz;
689     ny = tmp;
690   }
691   glEnd();
692 
693   // draw first cylinder cap
694   start_nx = 0;
695   start_ny = 1;
696   for (j=0; j<(n/4); j++) {
697     // get start_n2 = rotated start_n
698     float start_nx2 =  ca*start_nx + sa*start_ny;
699     float start_ny2 = -sa*start_nx + ca*start_ny;
700     // get n=start_n and n2=start_n2
701     nx = start_nx; ny = start_ny; nz = 0;
702     float nx2 = start_nx2, ny2 = start_ny2, nz2 = 0;
703     glBegin (GL_TRIANGLE_STRIP);
704     for (i=0; i<=n; i++) {
705       glNormal3d (ny2,nz2,nx2);
706       glVertex3d (ny2*r,nz2*r,l+nx2*r);
707       glNormal3d (ny,nz,nx);
708       glVertex3d (ny*r,nz*r,l+nx*r);
709       // rotate n,n2
710       tmp = ca*ny - sa*nz;
711       nz = sa*ny + ca*nz;
712       ny = tmp;
713       tmp = ca*ny2- sa*nz2;
714       nz2 = sa*ny2 + ca*nz2;
715       ny2 = tmp;
716     }
717     glEnd();
718     start_nx = start_nx2;
719     start_ny = start_ny2;
720   }
721 
722   // draw second cylinder cap
723   start_nx = 0;
724   start_ny = 1;
725   for (j=0; j<(n/4); j++) {
726     // get start_n2 = rotated start_n
727     float start_nx2 = ca*start_nx - sa*start_ny;
728     float start_ny2 = sa*start_nx + ca*start_ny;
729     // get n=start_n and n2=start_n2
730     nx = start_nx; ny = start_ny; nz = 0;
731     float nx2 = start_nx2, ny2 = start_ny2, nz2 = 0;
732     glBegin (GL_TRIANGLE_STRIP);
733     for (i=0; i<=n; i++) {
734       glNormal3d (ny,nz,nx);
735       glVertex3d (ny*r,nz*r,-l+nx*r);
736       glNormal3d (ny2,nz2,nx2);
737       glVertex3d (ny2*r,nz2*r,-l+nx2*r);
738       // rotate n,n2
739       tmp = ca*ny - sa*nz;
740       nz = sa*ny + ca*nz;
741       ny = tmp;
742       tmp = ca*ny2- sa*nz2;
743       nz2 = sa*ny2 + ca*nz2;
744       ny2 = tmp;
745     }
746     glEnd();
747     start_nx = start_nx2;
748     start_ny = start_ny2;
749   }
750 }
751 
752 
753 // draw a cylinder of length l and radius r, aligned along the z axis
754 
drawCylinder(float l,float r,float zoffset)755 static void drawCylinder (float l, float r, float zoffset)
756 {
757   int i;
758   float tmp,ny,nz,a,ca,sa;
759   const int n = 24;	// number of sides to the cylinder (divisible by 4)
760 
761   l *= 0.5;
762   a = float(M_PI*2.0)/float(n);
763   sa = (float) sin(a);
764   ca = (float) cos(a);
765 
766   // draw cylinder body
767   ny=1; nz=0;		  // normal vector = (0,ny,nz)
768   glBegin (GL_TRIANGLE_STRIP);
769   for (i=0; i<=n; i++) {
770     glNormal3d (ny,nz,0);
771     glVertex3d (ny*r,nz*r,l+zoffset);
772     glNormal3d (ny,nz,0);
773     glVertex3d (ny*r,nz*r,-l+zoffset);
774     // rotate ny,nz
775     tmp = ca*ny - sa*nz;
776     nz = sa*ny + ca*nz;
777     ny = tmp;
778   }
779   glEnd();
780 
781   // draw top cap
782   glShadeModel (GL_FLAT);
783   ny=1; nz=0;		  // normal vector = (0,ny,nz)
784   glBegin (GL_TRIANGLE_FAN);
785   glNormal3d (0,0,1);
786   glVertex3d (0,0,l+zoffset);
787   for (i=0; i<=n; i++) {
788     if (i==1 || i==n/2+1)
789       setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]);
790     glNormal3d (0,0,1);
791     glVertex3d (ny*r,nz*r,l+zoffset);
792     if (i==1 || i==n/2+1)
793       setColor (color[0],color[1],color[2],color[3]);
794 
795     // rotate ny,nz
796     tmp = ca*ny - sa*nz;
797     nz = sa*ny + ca*nz;
798     ny = tmp;
799   }
800   glEnd();
801 
802   // draw bottom cap
803   ny=1; nz=0;		  // normal vector = (0,ny,nz)
804   glBegin (GL_TRIANGLE_FAN);
805   glNormal3d (0,0,-1);
806   glVertex3d (0,0,-l+zoffset);
807   for (i=0; i<=n; i++) {
808     if (i==1 || i==n/2+1)
809       setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]);
810     glNormal3d (0,0,-1);
811     glVertex3d (ny*r,nz*r,-l+zoffset);
812     if (i==1 || i==n/2+1)
813       setColor (color[0],color[1],color[2],color[3]);
814 
815     // rotate ny,nz
816     tmp = ca*ny + sa*nz;
817     nz = -sa*ny + ca*nz;
818     ny = tmp;
819   }
820   glEnd();
821 }
822 
823 //***************************************************************************
824 // motion model
825 
826 // current camera position and orientation
827 static float view_xyz[3];	// position x,y,z
828 static float view_hpr[3];	// heading, pitch, roll (degrees)
829 
830 
831 // initialize the above variables
832 
initMotionModel()833 static void initMotionModel()
834 {
835   view_xyz[0] = 2;
836   view_xyz[1] = 0;
837   view_xyz[2] = 1;
838   view_hpr[0] = 180;
839   view_hpr[1] = 0;
840   view_hpr[2] = 0;
841 }
842 
843 
wrapCameraAngles()844 static void wrapCameraAngles()
845 {
846   for (int i=0; i<3; i++) {
847     while (view_hpr[i] > 180) view_hpr[i] -= 360;
848     while (view_hpr[i] < -180) view_hpr[i] += 360;
849   }
850 }
851 
852 
853 // call this to update the current camera position. the bits in `mode' say
854 // if the left (1), middle (2) or right (4) mouse button is pressed, and
855 // (deltax,deltay) is the amount by which the mouse pointer has moved.
856 
dsMotion(int mode,int deltax,int deltay)857 void dsMotion (int mode, int deltax, int deltay)
858 {
859   float side = 0.01f * float(deltax);
860   float fwd = (mode==4) ? (0.01f * float(deltay)) : 0.0f;
861   float s = (float) sin (view_hpr[0]*DEG_TO_RAD);
862   float c = (float) cos (view_hpr[0]*DEG_TO_RAD);
863 
864   if (mode==1) {
865     view_hpr[0] += float (deltax) * 0.5f;
866     view_hpr[1] += float (deltay) * 0.5f;
867   }
868   else {
869     view_xyz[0] += -s*side + c*fwd;
870     view_xyz[1] += c*side + s*fwd;
871     if (mode==2 || mode==5) view_xyz[2] += 0.01f * float(deltay);
872   }
873   wrapCameraAngles();
874 }
875 
876 //***************************************************************************
877 // drawing loop stuff
878 
879 // the current state:
880 //    0 = uninitialized
881 //    1 = dsSimulationLoop() called
882 //    2 = dsDrawFrame() called
883 static int current_state = 0;
884 
885 // textures and shadows
886 static int use_textures=1;		// 1 if textures to be drawn
887 static int use_shadows=1;		// 1 if shadows to be drawn
888 static Texture *sky_texture = 0;
889 static Texture *ground_texture = 0;
890 static Texture *wood_texture = 0;
891 static Texture *checkered_texture = 0;
892 
893 static Texture *texture[4+1]; // +1 since index 0 is not used
894 
895 
896 
897 #if !defined(macintosh) || defined(ODE_PLATFORM_OSX)
898 
dsStartGraphics(int width,int height,dsFunctions * fn)899 void dsStartGraphics (int width, int height, dsFunctions *fn)
900 {
901 
902   const char *prefix = DEFAULT_PATH_TO_TEXTURES;
903   if (fn->version >= 2 && fn->path_to_textures) prefix = fn->path_to_textures;
904   char *s = (char*) alloca (strlen(prefix) + 20);
905 
906   strcpy (s,prefix);
907   strcat (s,"/sky.ppm");
908   texture[DS_SKY] = sky_texture = new Texture (s);
909 
910   strcpy (s,prefix);
911   strcat (s,"/ground.ppm");
912   texture[DS_GROUND] = ground_texture = new Texture (s);
913 
914   strcpy (s,prefix);
915   strcat (s,"/wood.ppm");
916   texture[DS_WOOD] = wood_texture = new Texture (s);
917 
918   strcpy (s,prefix);
919   strcat (s,"/checkered.ppm");
920   texture[DS_CHECKERED] = checkered_texture = new Texture (s);
921 }
922 
923 #else // macintosh
924 
dsStartGraphics(int width,int height,dsFunctions * fn)925 void dsStartGraphics (int width, int height, dsFunctions *fn)
926 {
927 
928    // All examples build into the same dir
929    char *prefix = "::::drawstuff:textures";
930    char *s = (char*) alloca (strlen(prefix) + 20);
931 
932    strcpy (s,prefix);
933    strcat (s,":sky.ppm");
934    sky_texture = new Texture (s);
935 
936    strcpy (s,prefix);
937    strcat (s,":ground.ppm");
938    ground_texture = new Texture (s);
939 
940    strcpy (s,prefix);
941    strcat (s,":wood.ppm");
942    wood_texture = new Texture (s);
943 }
944 
945 #endif
946 
947 
dsStopGraphics()948 void dsStopGraphics()
949 {
950   delete sky_texture;
951   delete ground_texture;
952   delete wood_texture;
953   sky_texture = 0;
954   ground_texture = 0;
955   wood_texture = 0;
956 }
957 
958 
drawSky(float view_xyz[3])959 static void drawSky (float view_xyz[3])
960 {
961   glDisable (GL_LIGHTING);
962   if (use_textures) {
963     glEnable (GL_TEXTURE_2D);
964     sky_texture->bind (0);
965   }
966   else {
967     glDisable (GL_TEXTURE_2D);
968     glColor3f (0,0.5,1.0);
969   }
970 
971   // make sure sky depth is as far back as possible
972   glShadeModel (GL_FLAT);
973   glEnable (GL_DEPTH_TEST);
974   glDepthFunc (GL_LEQUAL);
975   glDepthRange (1,1);
976 
977   const float ssize = 1000.0f;
978   static float offset = 0.0f;
979 
980   float x = ssize*sky_scale;
981   float z = view_xyz[2] + sky_height;
982 
983   glBegin (GL_QUADS);
984   glNormal3f (0,0,-1);
985   glTexCoord2f (-x+offset,-x+offset);
986   glVertex3f (-ssize+view_xyz[0],-ssize+view_xyz[1],z);
987   glTexCoord2f (-x+offset,x+offset);
988   glVertex3f (-ssize+view_xyz[0],ssize+view_xyz[1],z);
989   glTexCoord2f (x+offset,x+offset);
990   glVertex3f (ssize+view_xyz[0],ssize+view_xyz[1],z);
991   glTexCoord2f (x+offset,-x+offset);
992   glVertex3f (ssize+view_xyz[0],-ssize+view_xyz[1],z);
993   glEnd();
994 
995   offset = offset + 0.002f;
996   if (offset > 1) offset -= 1;
997 
998   glDepthFunc (GL_LESS);
999   glDepthRange (0,1);
1000 }
1001 
1002 
drawGround()1003 static void drawGround()
1004 {
1005   glDisable (GL_LIGHTING);
1006   glShadeModel (GL_FLAT);
1007   glEnable (GL_DEPTH_TEST);
1008   glDepthFunc (GL_LESS);
1009   // glDepthRange (1,1);
1010 
1011   if (use_textures) {
1012     glEnable (GL_TEXTURE_2D);
1013     ground_texture->bind (0);
1014   }
1015   else {
1016     glDisable (GL_TEXTURE_2D);
1017     glColor3f (GROUND_R,GROUND_G,GROUND_B);
1018   }
1019 
1020   // ground fog seems to cause problems with TNT2 under windows
1021   /*
1022   GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1};
1023   glEnable (GL_FOG);
1024   glFogi (GL_FOG_MODE, GL_EXP2);
1025   glFogfv (GL_FOG_COLOR, fogColor);
1026   glFogf (GL_FOG_DENSITY, 0.05f);
1027   glHint (GL_FOG_HINT, GL_NICEST); // GL_DONT_CARE);
1028   glFogf (GL_FOG_START, 1.0);
1029   glFogf (GL_FOG_END, 5.0);
1030   */
1031 
1032   const float gsize = 100.0f;
1033   const float offset = 0; // -0.001f; ... polygon offsetting doesn't work well
1034 
1035   glBegin (GL_QUADS);
1036   glNormal3f (0,0,1);
1037   glTexCoord2f (-gsize*ground_scale + ground_ofsx,
1038 		-gsize*ground_scale + ground_ofsy);
1039   glVertex3f (-gsize,-gsize,offset);
1040   glTexCoord2f (gsize*ground_scale + ground_ofsx,
1041 		-gsize*ground_scale + ground_ofsy);
1042   glVertex3f (gsize,-gsize,offset);
1043   glTexCoord2f (gsize*ground_scale + ground_ofsx,
1044 		gsize*ground_scale + ground_ofsy);
1045   glVertex3f (gsize,gsize,offset);
1046   glTexCoord2f (-gsize*ground_scale + ground_ofsx,
1047 		gsize*ground_scale + ground_ofsy);
1048   glVertex3f (-gsize,gsize,offset);
1049   glEnd();
1050 
1051   glDisable (GL_FOG);
1052 }
1053 
1054 
drawPyramidGrid()1055 static void drawPyramidGrid()
1056 {
1057   // setup stuff
1058   glEnable (GL_LIGHTING);
1059   glDisable (GL_TEXTURE_2D);
1060   glShadeModel (GL_FLAT);
1061   glEnable (GL_DEPTH_TEST);
1062   glDepthFunc (GL_LESS);
1063 
1064   // draw the pyramid grid
1065   for (int i=-1; i<=1; i++) {
1066     for (int j=-1; j<=1; j++) {
1067       glPushMatrix();
1068       glTranslatef ((float)i,(float)j,(float)0);
1069       if (i==1 && j==0) setColor (1,0,0,1);
1070       else if (i==0 && j==1) setColor (0,0,1,1);
1071       else setColor (1,1,0,1);
1072       const float k = 0.03f;
1073       glBegin (GL_TRIANGLE_FAN);
1074       glNormal3f (0,-1,1);
1075       glVertex3f (0,0,k);
1076       glVertex3f (-k,-k,0);
1077       glVertex3f ( k,-k,0);
1078       glNormal3f (1,0,1);
1079       glVertex3f ( k, k,0);
1080       glNormal3f (0,1,1);
1081       glVertex3f (-k, k,0);
1082       glNormal3f (-1,0,1);
1083       glVertex3f (-k,-k,0);
1084       glEnd();
1085       glPopMatrix();
1086     }
1087   }
1088 }
1089 
1090 
dsDrawFrame(int width,int height,dsFunctions * fn,int pause)1091 void dsDrawFrame (int width, int height, dsFunctions *fn, int pause)
1092 {
1093   if (current_state < 1) dsDebug ("internal error");
1094   current_state = 2;
1095 
1096   // setup stuff
1097   glEnable (GL_LIGHTING);
1098   glEnable (GL_LIGHT0);
1099   glDisable (GL_TEXTURE_2D);
1100   glDisable (GL_TEXTURE_GEN_S);
1101   glDisable (GL_TEXTURE_GEN_T);
1102   glShadeModel (GL_FLAT);
1103   glEnable (GL_DEPTH_TEST);
1104   glDepthFunc (GL_LESS);
1105   glEnable (GL_CULL_FACE);
1106   glCullFace (GL_BACK);
1107   glFrontFace (GL_CCW);
1108 
1109   // setup viewport
1110   glViewport (0,0,width,height);
1111   glMatrixMode (GL_PROJECTION);
1112   glLoadIdentity();
1113   const float vnear = 0.1f;
1114   const float vfar = 100.0f;
1115   const float k = 0.8f;     // view scale, 1 = +/- 45 degrees
1116   if (width >= height) {
1117     float k2 = float(height)/float(width);
1118     glFrustum (-vnear*k,vnear*k,-vnear*k*k2,vnear*k*k2,vnear,vfar);
1119   }
1120   else {
1121     float k2 = float(width)/float(height);
1122     glFrustum (-vnear*k*k2,vnear*k*k2,-vnear*k,vnear*k,vnear,vfar);
1123   }
1124 
1125   // setup lights. it makes a difference whether this is done in the
1126   // GL_PROJECTION matrix mode (lights are scene relative) or the
1127   // GL_MODELVIEW matrix mode (lights are camera relative, bad!).
1128   static GLfloat light_ambient[] = { 0.5, 0.5, 0.5, 1.0 };
1129   static GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
1130   static GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
1131   glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient);
1132   glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse);
1133   glLightfv (GL_LIGHT0, GL_SPECULAR, light_specular);
1134   glColor3f (1.0, 1.0, 1.0);
1135 
1136   // clear the window
1137   glClearColor (0.5,0.5,0.5,0);
1138   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1139 
1140   // snapshot camera position (in MS Windows it is changed by the GUI thread)
1141   float view2_xyz[3];
1142   float view2_hpr[3];
1143   memcpy (view2_xyz,view_xyz,sizeof(float)*3);
1144   memcpy (view2_hpr,view_hpr,sizeof(float)*3);
1145 
1146   // go to GL_MODELVIEW matrix mode and set the camera
1147   glMatrixMode (GL_MODELVIEW);
1148   glLoadIdentity();
1149   setCamera (view2_xyz[0],view2_xyz[1],view2_xyz[2],
1150 	     view2_hpr[0],view2_hpr[1],view2_hpr[2]);
1151 
1152   // set the light position (for some reason we have to do this in model view.
1153   static GLfloat light_position[] = { LIGHTX, LIGHTY, 1.0, 0.0 };
1154   glLightfv (GL_LIGHT0, GL_POSITION, light_position);
1155 
1156   // draw the background (ground, sky etc)
1157   drawSky (view2_xyz);
1158   drawGround();
1159 
1160   // draw the little markers on the ground
1161   drawPyramidGrid();
1162 
1163   // leave openGL in a known state - flat shaded white, no textures
1164   glEnable (GL_LIGHTING);
1165   glDisable (GL_TEXTURE_2D);
1166   glShadeModel (GL_FLAT);
1167   glEnable (GL_DEPTH_TEST);
1168   glDepthFunc (GL_LESS);
1169   glColor3f (1,1,1);
1170   setColor (1,1,1,1);
1171 
1172   // draw the rest of the objects. set drawing state first.
1173   color[0] = 1;
1174   color[1] = 1;
1175   color[2] = 1;
1176   color[3] = 1;
1177   tnum = 0;
1178   if (fn->step) fn->step (pause);
1179 }
1180 
1181 
dsGetShadows()1182 int dsGetShadows()
1183 {
1184   return use_shadows;
1185 }
1186 
1187 
dsSetShadows(int a)1188 void dsSetShadows (int a)
1189 {
1190   use_shadows = (a != 0);
1191 }
1192 
1193 
dsGetTextures()1194 int dsGetTextures()
1195 {
1196   return use_textures;
1197 }
1198 
1199 
dsSetTextures(int a)1200 void dsSetTextures (int a)
1201 {
1202   use_textures = (a != 0);
1203 }
1204 
1205 //***************************************************************************
1206 // C interface
1207 
1208 // sets lighting and texture modes, sets current color
setupDrawingMode()1209 static void setupDrawingMode()
1210 {
1211   glEnable (GL_LIGHTING);
1212   if (tnum) {
1213     if (use_textures) {
1214       glEnable (GL_TEXTURE_2D);
1215       texture[tnum]->bind (1);
1216       glEnable (GL_TEXTURE_GEN_S);
1217       glEnable (GL_TEXTURE_GEN_T);
1218       glTexGeni (GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
1219       glTexGeni (GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
1220       static GLfloat s_params[4] = {1.0f,1.0f,0.0f,1};
1221       static GLfloat t_params[4] = {0.817f,-0.817f,0.817f,1};
1222       glTexGenfv (GL_S,GL_OBJECT_PLANE,s_params);
1223       glTexGenfv (GL_T,GL_OBJECT_PLANE,t_params);
1224     }
1225     else {
1226       glDisable (GL_TEXTURE_2D);
1227     }
1228   }
1229   else {
1230     glDisable (GL_TEXTURE_2D);
1231   }
1232   setColor (color[0],color[1],color[2],color[3]);
1233 
1234   if (color[3] < 1) {
1235     glEnable (GL_BLEND);
1236     glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1237   }
1238   else {
1239     glDisable (GL_BLEND);
1240   }
1241 }
1242 
1243 
setShadowDrawingMode()1244 static void setShadowDrawingMode()
1245 {
1246   glDisable (GL_LIGHTING);
1247   if (use_textures) {
1248     glEnable (GL_TEXTURE_2D);
1249     ground_texture->bind (1);
1250     glColor3f (SHADOW_INTENSITY,SHADOW_INTENSITY,SHADOW_INTENSITY);
1251     glEnable (GL_TEXTURE_2D);
1252     glEnable (GL_TEXTURE_GEN_S);
1253     glEnable (GL_TEXTURE_GEN_T);
1254     glTexGeni (GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
1255     glTexGeni (GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
1256     static GLfloat s_params[4] = {ground_scale,0,0,ground_ofsx};
1257     static GLfloat t_params[4] = {0,ground_scale,0,ground_ofsy};
1258     glTexGenfv (GL_S,GL_EYE_PLANE,s_params);
1259     glTexGenfv (GL_T,GL_EYE_PLANE,t_params);
1260   }
1261   else {
1262     glDisable (GL_TEXTURE_2D);
1263     glColor3f (GROUND_R*SHADOW_INTENSITY,GROUND_G*SHADOW_INTENSITY,
1264 	       GROUND_B*SHADOW_INTENSITY);
1265   }
1266   glDepthRange (0,0.9999);
1267 }
1268 
1269 
dsSimulationLoop(int argc,char ** argv,int window_width,int window_height,dsFunctions * fn)1270 extern "C" void dsSimulationLoop (int argc, char **argv,
1271 				  int window_width, int window_height,
1272 				  dsFunctions *fn)
1273 {
1274   if (current_state != 0) dsError ("dsSimulationLoop() called more than once");
1275   current_state = 1;
1276 
1277   // look for flags that apply to us
1278   int initial_pause = 0;
1279   for (int i=1; i<argc; i++) {
1280     if (strcmp(argv[i],"-notex")==0) use_textures = 0;
1281     if (strcmp(argv[i],"-noshadow")==0) use_shadows = 0;
1282     if (strcmp(argv[i],"-noshadows")==0) use_shadows = 0;
1283     if (strcmp(argv[i],"-pause")==0) initial_pause = 1;
1284     if (strcmp(argv[i],"-texturepath")==0)
1285       if (++i < argc)
1286         fn->path_to_textures = argv[i];
1287   }
1288 
1289   if (fn->version > DS_VERSION)
1290     dsDebug ("bad version number in dsFunctions structure");
1291 
1292   initMotionModel();
1293   dsPlatformSimLoop (window_width,window_height,fn,initial_pause);
1294 
1295   current_state = 0;
1296 }
1297 
1298 
dsSetViewpoint(float xyz[3],float hpr[3])1299 extern "C" void dsSetViewpoint (float xyz[3], float hpr[3])
1300 {
1301   if (current_state < 1) dsError ("dsSetViewpoint() called before simulation started");
1302   if (xyz) {
1303     view_xyz[0] = xyz[0];
1304     view_xyz[1] = xyz[1];
1305     view_xyz[2] = xyz[2];
1306   }
1307   if (hpr) {
1308     view_hpr[0] = hpr[0];
1309     view_hpr[1] = hpr[1];
1310     view_hpr[2] = hpr[2];
1311     wrapCameraAngles();
1312   }
1313 }
1314 
1315 
dsGetViewpoint(float xyz[3],float hpr[3])1316 extern "C" void dsGetViewpoint (float xyz[3], float hpr[3])
1317 {
1318   if (current_state < 1) dsError ("dsGetViewpoint() called before simulation started");
1319   if (xyz) {
1320     xyz[0] = view_xyz[0];
1321     xyz[1] = view_xyz[1];
1322     xyz[2] = view_xyz[2];
1323   }
1324   if (hpr) {
1325     hpr[0] = view_hpr[0];
1326     hpr[1] = view_hpr[1];
1327     hpr[2] = view_hpr[2];
1328   }
1329 }
1330 
1331 
dsSetTexture(int texture_number)1332 extern "C" void dsSetTexture (int texture_number)
1333 {
1334   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1335   tnum = texture_number;
1336 }
1337 
1338 
dsSetColor(float red,float green,float blue)1339 extern "C" void dsSetColor (float red, float green, float blue)
1340 {
1341   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1342   color[0] = red;
1343   color[1] = green;
1344   color[2] = blue;
1345   color[3] = 1;
1346 }
1347 
1348 
dsSetColorAlpha(float red,float green,float blue,float alpha)1349 extern "C" void dsSetColorAlpha (float red, float green, float blue,
1350 				 float alpha)
1351 {
1352   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1353   color[0] = red;
1354   color[1] = green;
1355   color[2] = blue;
1356   color[3] = alpha;
1357 }
1358 
1359 
dsDrawBox(const float pos[3],const float R[12],const float sides[3])1360 extern "C" void dsDrawBox (const float pos[3], const float R[12],
1361 			   const float sides[3])
1362 {
1363   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1364   setupDrawingMode();
1365   glShadeModel (GL_FLAT);
1366   setTransform (pos,R);
1367   drawBox (sides);
1368   glPopMatrix();
1369 
1370   if (use_shadows) {
1371     setShadowDrawingMode();
1372     setShadowTransform();
1373     setTransform (pos,R);
1374     drawBox (sides);
1375     glPopMatrix();
1376     glPopMatrix();
1377     glDepthRange (0,1);
1378   }
1379 }
1380 
dsDrawConvex(const float pos[3],const float R[12],float * _planes,unsigned int _planecount,float * _points,unsigned int _pointcount,unsigned int * _polygons)1381 extern "C" void dsDrawConvex (const float pos[3], const float R[12],
1382 			      float *_planes,unsigned int _planecount,
1383 			      float *_points,
1384 			      unsigned int _pointcount,
1385 			      unsigned int *_polygons)
1386 {
1387   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1388   setupDrawingMode();
1389   glShadeModel (GL_FLAT);
1390   setTransform (pos,R);
1391   drawConvex(_planes,_planecount,_points,_pointcount,_polygons);
1392   glPopMatrix();
1393   if (use_shadows) {
1394     setShadowDrawingMode();
1395     setShadowTransform();
1396     setTransform (pos,R);
1397     drawConvex(_planes,_planecount,_points,_pointcount,_polygons);
1398     glPopMatrix();
1399     glPopMatrix();
1400     glDepthRange (0,1);
1401   }
1402 }
1403 
1404 
dsDrawSphere(const float pos[3],const float R[12],float radius)1405 extern "C" void dsDrawSphere (const float pos[3], const float R[12],
1406 			      float radius)
1407 {
1408   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1409   setupDrawingMode();
1410   glEnable (GL_NORMALIZE);
1411   glShadeModel (GL_SMOOTH);
1412   setTransform (pos,R);
1413   glScaled (radius,radius,radius);
1414   drawSphere();
1415   glPopMatrix();
1416   glDisable (GL_NORMALIZE);
1417 
1418   // draw shadows
1419   if (use_shadows) {
1420     glDisable (GL_LIGHTING);
1421     if (use_textures) {
1422       ground_texture->bind (1);
1423       glEnable (GL_TEXTURE_2D);
1424       glDisable (GL_TEXTURE_GEN_S);
1425       glDisable (GL_TEXTURE_GEN_T);
1426       glColor3f (SHADOW_INTENSITY,SHADOW_INTENSITY,SHADOW_INTENSITY);
1427     }
1428     else {
1429       glDisable (GL_TEXTURE_2D);
1430       glColor3f (GROUND_R*SHADOW_INTENSITY,GROUND_G*SHADOW_INTENSITY,
1431 		 GROUND_B*SHADOW_INTENSITY);
1432     }
1433     glShadeModel (GL_FLAT);
1434     glDepthRange (0,0.9999);
1435     drawSphereShadow (pos[0],pos[1],pos[2],radius);
1436     glDepthRange (0,1);
1437   }
1438 }
1439 
1440 
dsDrawTriangle(const float pos[3],const float R[12],const float * v0,const float * v1,const float * v2,int solid)1441 extern "C" void dsDrawTriangle (const float pos[3], const float R[12],
1442 				const float *v0, const float *v1,
1443 				const float *v2, int solid)
1444 {
1445   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1446   setupDrawingMode();
1447   glShadeModel (GL_FLAT);
1448   setTransform (pos,R);
1449   drawTriangle (v0, v1, v2, solid);
1450   glPopMatrix();
1451 }
1452 
1453 
dsDrawCylinder(const float pos[3],const float R[12],float length,float radius)1454 extern "C" void dsDrawCylinder (const float pos[3], const float R[12],
1455 				float length, float radius)
1456 {
1457   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1458   setupDrawingMode();
1459   glShadeModel (GL_SMOOTH);
1460   setTransform (pos,R);
1461   drawCylinder (length,radius,0);
1462   glPopMatrix();
1463 
1464   if (use_shadows) {
1465     setShadowDrawingMode();
1466     setShadowTransform();
1467     setTransform (pos,R);
1468     drawCylinder (length,radius,0);
1469     glPopMatrix();
1470     glPopMatrix();
1471     glDepthRange (0,1);
1472   }
1473 }
1474 
1475 
dsDrawCapsule(const float pos[3],const float R[12],float length,float radius)1476 extern "C" void dsDrawCapsule (const float pos[3], const float R[12],
1477 				      float length, float radius)
1478 {
1479   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1480   setupDrawingMode();
1481   glShadeModel (GL_SMOOTH);
1482   setTransform (pos,R);
1483   drawCapsule (length,radius);
1484   glPopMatrix();
1485 
1486   if (use_shadows) {
1487     setShadowDrawingMode();
1488     setShadowTransform();
1489     setTransform (pos,R);
1490     drawCapsule (length,radius);
1491     glPopMatrix();
1492     glPopMatrix();
1493     glDepthRange (0,1);
1494   }
1495 }
1496 
1497 
drawLine(const float pos1[3],const float pos2[3])1498 static void drawLine(const float pos1[3], const float pos2[3])
1499 {
1500   glDisable (GL_LIGHTING);
1501   glLineWidth (2);
1502   glShadeModel (GL_FLAT);
1503   glBegin (GL_LINES);
1504   glVertex3f (pos1[0],pos1[1],pos1[2]);
1505   glVertex3f (pos2[0],pos2[1],pos2[2]);
1506   glEnd();
1507 }
1508 
1509 
dsDrawLine(const float pos1[3],const float pos2[3])1510 extern "C" void dsDrawLine (const float pos1[3], const float pos2[3])
1511 {
1512   setupDrawingMode();
1513   glColor4f(color[0], color[1], color[2], color[3]);
1514   drawLine(pos1, pos2);
1515 
1516   if (use_shadows) {
1517     setShadowDrawingMode();
1518     setShadowTransform();
1519 
1520     drawLine(pos1, pos2);
1521 
1522     glPopMatrix();
1523     glDepthRange (0,1);
1524   }
1525 }
1526 
1527 
dsDrawBoxD(const double pos[3],const double R[12],const double sides[3])1528 extern "C" void dsDrawBoxD (const double pos[3], const double R[12],
1529                             const double sides[3])
1530 {
1531   int i;
1532   float pos2[3],R2[12],fsides[3];
1533   for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1534   for (i=0; i<12; i++) R2[i]=(float)R[i];
1535   for (i=0; i<3; i++) fsides[i]=(float)sides[i];
1536   dsDrawBox (pos2,R2,fsides);
1537 }
1538 
dsDrawConvexD(const double pos[3],const double R[12],double * _planes,unsigned int _planecount,double * _points,unsigned int _pointcount,unsigned int * _polygons)1539 extern "C" void dsDrawConvexD (const double pos[3], const double R[12],
1540 			       double *_planes,unsigned int _planecount,
1541 			       double *_points,
1542 			       unsigned int _pointcount,
1543 			       unsigned int *_polygons)
1544 {
1545   if (current_state != 2) dsError ("drawing function called outside simulation loop");
1546   setupDrawingMode();
1547   glShadeModel (GL_FLAT);
1548   setTransformD (pos,R);
1549   drawConvexD(_planes,_planecount,_points,_pointcount,_polygons);
1550   glPopMatrix();
1551   if (use_shadows) {
1552     setShadowDrawingMode();
1553     setShadowTransform();
1554     setTransformD (pos,R);
1555     drawConvexD(_planes,_planecount,_points,_pointcount,_polygons);
1556     glPopMatrix();
1557     glPopMatrix();
1558     glDepthRange (0,1);
1559   }
1560 }
1561 
dsDrawSphereD(const double pos[3],const double R[12],float radius)1562 void dsDrawSphereD (const double pos[3], const double R[12], float radius)
1563 {
1564   int i;
1565   float pos2[3],R2[12];
1566   for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1567   for (i=0; i<12; i++) R2[i]=(float)R[i];
1568   dsDrawSphere (pos2,R2,radius);
1569 }
1570 
1571 
dsDrawTriangleD(const double pos[3],const double R[12],const double * v0,const double * v1,const double * v2,int solid)1572 void dsDrawTriangleD (const double pos[3], const double R[12],
1573 				 const double *v0, const double *v1,
1574 				 const double *v2, int solid)
1575 {
1576   int i;
1577   float pos2[3],R2[12];
1578   for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1579   for (i=0; i<12; i++) R2[i]=(float)R[i];
1580 
1581   setupDrawingMode();
1582   glShadeModel (GL_FLAT);
1583   setTransform (pos2,R2);
1584   drawTriangleD (v0, v1, v2, solid);
1585   glPopMatrix();
1586 }
1587 
1588 
dsDrawCylinderD(const double pos[3],const double R[12],float length,float radius)1589 void dsDrawCylinderD (const double pos[3], const double R[12],
1590 		      float length, float radius)
1591 {
1592   int i;
1593   float pos2[3],R2[12];
1594   for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1595   for (i=0; i<12; i++) R2[i]=(float)R[i];
1596   dsDrawCylinder (pos2,R2,length,radius);
1597 }
1598 
1599 
dsDrawCapsuleD(const double pos[3],const double R[12],float length,float radius)1600 void dsDrawCapsuleD (const double pos[3], const double R[12],
1601 			    float length, float radius)
1602 {
1603   int i;
1604   float pos2[3],R2[12];
1605   for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1606   for (i=0; i<12; i++) R2[i]=(float)R[i];
1607   dsDrawCapsule (pos2,R2,length,radius);
1608 }
1609 
1610 
dsDrawLineD(const double _pos1[3],const double _pos2[3])1611 void dsDrawLineD (const double _pos1[3], const double _pos2[3])
1612 {
1613   int i;
1614   float pos1[3],pos2[3];
1615   for (i=0; i<3; i++) pos1[i]=(float)_pos1[i];
1616   for (i=0; i<3; i++) pos2[i]=(float)_pos2[i];
1617   dsDrawLine (pos1,pos2);
1618 }
1619 
1620 
dsSetSphereQuality(int n)1621 void dsSetSphereQuality (int n)
1622 {
1623   sphere_quality = n;
1624 }
1625 
1626 
dsSetCapsuleQuality(int n)1627 void dsSetCapsuleQuality (int n)
1628 {
1629   capped_cylinder_quality = n;
1630 }
1631 
dsSetDrawMode(int mode)1632 void dsSetDrawMode(int mode)
1633 {
1634   switch(mode)
1635     {
1636     case DS_POLYFILL:
1637       glPolygonMode(GL_FRONT,GL_FILL);
1638       break;
1639     case DS_WIREFRAME:
1640       glPolygonMode(GL_FRONT,GL_LINE);
1641       break;
1642     }
1643 }
1644