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