added a -texturepath option to drawstuff
[ode.git] / drawstuff / src / drawstuff.cpp
blobb3c1f41a2c27f3184eb99aa2c12d4060626ba9ae
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 *************************************************************************/
25 simple graphics.
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
33 TODO
34 ----
36 manage openGL state changes better
40 #ifdef WIN32
41 #include <windows.h>
42 #endif
44 #include <ode/ode.h>
45 #include "config.h"
46 #ifdef HAVE_APPLE_OPENGL_FRAMEWORK
47 #include <OpenGL/gl.h>
48 #include <OpenGL/glu.h>
49 #else
50 #include <GL/gl.h>
51 #include <GL/glu.h>
52 #endif
54 #include "drawstuff/drawstuff.h"
55 #include "internal.h"
57 //***************************************************************************
58 // misc
60 #ifndef DEFAULT_PATH_TO_TEXTURES
61 #if 0
62 #define DEFAULT_PATH_TO_TEXTURES "..\\textures\\"
63 #else
64 #define DEFAULT_PATH_TO_TEXTURES "../textures/"
65 #endif
66 #endif
68 #ifndef M_PI
69 #define M_PI (3.14159265358979323846)
70 #endif
72 // constants to convert degrees to radians and the reverse
73 #define RAD_TO_DEG (180.0/M_PI)
74 #define DEG_TO_RAD (M_PI/180.0)
76 // light vector. LIGHTZ is implicitly 1
77 #define LIGHTX (1.0f)
78 #define LIGHTY (0.4f)
80 // ground and sky
81 #define SHADOW_INTENSITY (0.65f)
82 #define GROUND_R (0.5f) // ground color for when there's no texture
83 #define GROUND_G (0.5f)
84 #define GROUND_B (0.3f)
86 const float ground_scale = 1.0f/1.0f; // ground texture scale (1/size)
87 const float ground_ofsx = 0.5; // offset of ground texture
88 const float ground_ofsy = 0.5;
89 const float sky_scale = 1.0f/4.0f; // sky texture scale (1/size)
90 const float sky_height = 1.0f; // sky height above viewpoint
92 //***************************************************************************
93 // misc mathematics stuff
95 static void normalizeVector3 (float v[3])
97 float len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
98 if (len <= 0.0f) {
99 v[0] = 1;
100 v[1] = 0;
101 v[2] = 0;
103 else {
104 len = 1.0f / (float)sqrt(len);
105 v[0] *= len;
106 v[1] *= len;
107 v[2] *= len;
111 //***************************************************************************
112 // PPM image object
114 typedef unsigned char byte;
116 class Image {
117 int image_width,image_height;
118 byte *image_data;
119 public:
120 Image (char *filename);
121 // load from PPM file
122 ~Image();
123 int width() { return image_width; }
124 int height() { return image_height; }
125 byte *data() { return image_data; }
129 // skip over whitespace and comments in a stream.
131 static void skipWhiteSpace (char *filename, FILE *f)
133 int c,d;
134 for(;;) {
135 c = fgetc(f);
136 if (c==EOF) dsError ("unexpected end of file in \"%s\"",filename);
138 // skip comments
139 if (c == '#') {
140 do {
141 d = fgetc(f);
142 if (d==EOF) dsError ("unexpected end of file in \"%s\"",filename);
143 } while (d != '\n');
144 continue;
147 if (c > ' ') {
148 ungetc (c,f);
149 return;
155 // read a number from a stream, this return 0 if there is none (that's okay
156 // because 0 is a bad value for all PPM numbers anyway).
158 static int readNumber (char *filename, FILE *f)
160 int c,n=0;
161 for(;;) {
162 c = fgetc(f);
163 if (c==EOF) dsError ("unexpected end of file in \"%s\"",filename);
164 if (c >= '0' && c <= '9') n = n*10 + (c - '0');
165 else {
166 ungetc (c,f);
167 return n;
173 Image::Image (char *filename)
175 FILE *f = fopen (filename,"rb");
176 if (!f) dsError ("Can't open image file `%s'",filename);
178 // read in header
179 if (fgetc(f) != 'P' || fgetc(f) != '6')
180 dsError ("image file \"%s\" is not a binary PPM (no P6 header)",filename);
181 skipWhiteSpace (filename,f);
183 // read in image parameters
184 image_width = readNumber (filename,f);
185 skipWhiteSpace (filename,f);
186 image_height = readNumber (filename,f);
187 skipWhiteSpace (filename,f);
188 int max_value = readNumber (filename,f);
190 // check values
191 if (image_width < 1 || image_height < 1)
192 dsError ("bad image file \"%s\"",filename);
193 if (max_value != 255)
194 dsError ("image file \"%s\" must have color range of 255",filename);
196 // read either nothing, LF (10), or CR,LF (13,10)
197 int c = fgetc(f);
198 if (c == 10) {
199 // LF
201 else if (c == 13) {
202 // CR
203 c = fgetc(f);
204 if (c != 10) ungetc (c,f);
206 else ungetc (c,f);
208 // read in rest of data
209 image_data = new byte [image_width*image_height*3];
210 if (fread (image_data,image_width*image_height*3,1,f) != 1)
211 dsError ("Can not read data from image file `%s'",filename);
212 fclose (f);
216 Image::~Image()
218 delete[] image_data;
221 //***************************************************************************
222 // Texture object.
224 class Texture {
225 Image *image;
226 GLuint name;
227 public:
228 Texture (char *filename);
229 ~Texture();
230 void bind (int modulate);
234 Texture::Texture (char *filename)
236 image = new Image (filename);
237 glGenTextures (1,&name);
238 glBindTexture (GL_TEXTURE_2D,name);
240 // set pixel unpacking mode
241 glPixelStorei (GL_UNPACK_SWAP_BYTES, 0);
242 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
243 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
244 glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
245 glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
247 // glTexImage2D (GL_TEXTURE_2D, 0, 3, image->width(), image->height(), 0,
248 // GL_RGB, GL_UNSIGNED_BYTE, image->data());
249 gluBuild2DMipmaps (GL_TEXTURE_2D, 3, image->width(), image->height(),
250 GL_RGB, GL_UNSIGNED_BYTE, image->data());
252 // set texture parameters - will these also be bound to the texture???
253 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
254 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
256 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
257 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
258 GL_LINEAR_MIPMAP_LINEAR);
260 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
264 Texture::~Texture()
266 delete image;
267 glDeleteTextures (1,&name);
271 void Texture::bind (int modulate)
273 glBindTexture (GL_TEXTURE_2D,name);
274 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
275 modulate ? GL_MODULATE : GL_DECAL);
278 //***************************************************************************
279 // the current drawing state (for when the user's step function is drawing)
281 static float color[4] = {0,0,0,0}; // current r,g,b,alpha color
282 static int tnum = 0; // current texture number
284 //***************************************************************************
285 // OpenGL utility stuff
287 static void setCamera (float x, float y, float z, float h, float p, float r)
289 glMatrixMode (GL_MODELVIEW);
290 glLoadIdentity();
291 glRotatef (90, 0,0,1);
292 glRotatef (90, 0,1,0);
293 glRotatef (r, 1,0,0);
294 glRotatef (p, 0,1,0);
295 glRotatef (-h, 0,0,1);
296 glTranslatef (-x,-y,-z);
300 // sets the material color, not the light color
302 static void setColor (float r, float g, float b, float alpha)
304 GLfloat light_ambient[4],light_diffuse[4],light_specular[4];
305 light_ambient[0] = r*0.3f;
306 light_ambient[1] = g*0.3f;
307 light_ambient[2] = b*0.3f;
308 light_ambient[3] = alpha;
309 light_diffuse[0] = r*0.7f;
310 light_diffuse[1] = g*0.7f;
311 light_diffuse[2] = b*0.7f;
312 light_diffuse[3] = alpha;
313 light_specular[0] = r*0.2f;
314 light_specular[1] = g*0.2f;
315 light_specular[2] = b*0.2f;
316 light_specular[3] = alpha;
317 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, light_ambient);
318 glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, light_diffuse);
319 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, light_specular);
320 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 5.0f);
324 static void setTransform (const float pos[3], const float R[12])
326 GLfloat matrix[16];
327 matrix[0]=R[0];
328 matrix[1]=R[4];
329 matrix[2]=R[8];
330 matrix[3]=0;
331 matrix[4]=R[1];
332 matrix[5]=R[5];
333 matrix[6]=R[9];
334 matrix[7]=0;
335 matrix[8]=R[2];
336 matrix[9]=R[6];
337 matrix[10]=R[10];
338 matrix[11]=0;
339 matrix[12]=pos[0];
340 matrix[13]=pos[1];
341 matrix[14]=pos[2];
342 matrix[15]=1;
343 glPushMatrix();
344 glMultMatrixf (matrix);
346 static void setTransformD (const double pos[3], const double R[12])
348 GLdouble matrix[16];
349 matrix[0]=R[0];
350 matrix[1]=R[4];
351 matrix[2]=R[8];
352 matrix[3]=0;
353 matrix[4]=R[1];
354 matrix[5]=R[5];
355 matrix[6]=R[9];
356 matrix[7]=0;
357 matrix[8]=R[2];
358 matrix[9]=R[6];
359 matrix[10]=R[10];
360 matrix[11]=0;
361 matrix[12]=pos[0];
362 matrix[13]=pos[1];
363 matrix[14]=pos[2];
364 matrix[15]=1;
365 glPushMatrix();
366 glMultMatrixd (matrix);
370 // set shadow projection transform
372 static void setShadowTransform()
374 GLfloat matrix[16];
375 for (int i=0; i<16; i++) matrix[i] = 0;
376 matrix[0]=1;
377 matrix[5]=1;
378 matrix[8]=-LIGHTX;
379 matrix[9]=-LIGHTY;
380 matrix[15]=1;
381 glPushMatrix();
382 glMultMatrixf (matrix);
385 static void drawConvex (float *_planes,unsigned int _planecount,
386 float *_points,
387 unsigned int _pointcount,
388 unsigned int *_polygons)
390 unsigned int polyindex=0;
391 for(unsigned int i=0;i<_planecount;++i)
393 unsigned int pointcount=_polygons[polyindex];
394 polyindex++;
395 glBegin (GL_POLYGON);
396 glNormal3f(_planes[(i*4)+0],
397 _planes[(i*4)+1],
398 _planes[(i*4)+2]);
399 for(unsigned int j=0;j<pointcount;++j)
401 glVertex3f(_points[_polygons[polyindex]*3],
402 _points[(_polygons[polyindex]*3)+1],
403 _points[(_polygons[polyindex]*3)+2]);
404 polyindex++;
406 glEnd();
410 static void drawConvexD (double *_planes,unsigned int _planecount,
411 double *_points,
412 unsigned int _pointcount,
413 unsigned int *_polygons)
415 unsigned int polyindex=0;
416 for(unsigned int i=0;i<_planecount;++i)
418 unsigned int pointcount=_polygons[polyindex];
419 polyindex++;
420 glBegin (GL_POLYGON);
421 glNormal3d(_planes[(i*4)+0],
422 _planes[(i*4)+1],
423 _planes[(i*4)+2]);
424 for(unsigned int j=0;j<pointcount;++j)
426 glVertex3d(_points[_polygons[polyindex]*3],
427 _points[(_polygons[polyindex]*3)+1],
428 _points[(_polygons[polyindex]*3)+2]);
429 polyindex++;
431 glEnd();
435 static void drawBox (const float sides[3])
437 float lx = sides[0]*0.5f;
438 float ly = sides[1]*0.5f;
439 float lz = sides[2]*0.5f;
441 // sides
442 glBegin (GL_TRIANGLE_STRIP);
443 glNormal3f (-1,0,0);
444 glVertex3f (-lx,-ly,-lz);
445 glVertex3f (-lx,-ly,lz);
446 glVertex3f (-lx,ly,-lz);
447 glVertex3f (-lx,ly,lz);
448 glNormal3f (0,1,0);
449 glVertex3f (lx,ly,-lz);
450 glVertex3f (lx,ly,lz);
451 glNormal3f (1,0,0);
452 glVertex3f (lx,-ly,-lz);
453 glVertex3f (lx,-ly,lz);
454 glNormal3f (0,-1,0);
455 glVertex3f (-lx,-ly,-lz);
456 glVertex3f (-lx,-ly,lz);
457 glEnd();
459 // top face
460 glBegin (GL_TRIANGLE_FAN);
461 glNormal3f (0,0,1);
462 glVertex3f (-lx,-ly,lz);
463 glVertex3f (lx,-ly,lz);
464 glVertex3f (lx,ly,lz);
465 glVertex3f (-lx,ly,lz);
466 glEnd();
468 // bottom face
469 glBegin (GL_TRIANGLE_FAN);
470 glNormal3f (0,0,-1);
471 glVertex3f (-lx,-ly,-lz);
472 glVertex3f (-lx,ly,-lz);
473 glVertex3f (lx,ly,-lz);
474 glVertex3f (lx,-ly,-lz);
475 glEnd();
479 // This is recursively subdivides a triangular area (vertices p1,p2,p3) into
480 // smaller triangles, and then draws the triangles. All triangle vertices are
481 // normalized to a distance of 1.0 from the origin (p1,p2,p3 are assumed
482 // to be already normalized). Note this is not super-fast because it draws
483 // triangles rather than triangle strips.
485 static void drawPatch (float p1[3], float p2[3], float p3[3], int level)
487 int i;
488 if (level > 0) {
489 float q1[3],q2[3],q3[3]; // sub-vertices
490 for (i=0; i<3; i++) {
491 q1[i] = 0.5f*(p1[i]+p2[i]);
492 q2[i] = 0.5f*(p2[i]+p3[i]);
493 q3[i] = 0.5f*(p3[i]+p1[i]);
495 float length1 = (float)(1.0/sqrt(q1[0]*q1[0]+q1[1]*q1[1]+q1[2]*q1[2]));
496 float length2 = (float)(1.0/sqrt(q2[0]*q2[0]+q2[1]*q2[1]+q2[2]*q2[2]));
497 float length3 = (float)(1.0/sqrt(q3[0]*q3[0]+q3[1]*q3[1]+q3[2]*q3[2]));
498 for (i=0; i<3; i++) {
499 q1[i] *= length1;
500 q2[i] *= length2;
501 q3[i] *= length3;
503 drawPatch (p1,q1,q3,level-1);
504 drawPatch (q1,p2,q2,level-1);
505 drawPatch (q1,q2,q3,level-1);
506 drawPatch (q3,q2,p3,level-1);
508 else {
509 glNormal3f (p1[0],p1[1],p1[2]);
510 glVertex3f (p1[0],p1[1],p1[2]);
511 glNormal3f (p2[0],p2[1],p2[2]);
512 glVertex3f (p2[0],p2[1],p2[2]);
513 glNormal3f (p3[0],p3[1],p3[2]);
514 glVertex3f (p3[0],p3[1],p3[2]);
519 // draw a sphere of radius 1
521 static int sphere_quality = 1;
523 static void drawSphere()
525 // icosahedron data for an icosahedron of radius 1.0
526 # define ICX 0.525731112119133606f
527 # define ICZ 0.850650808352039932f
528 static GLfloat idata[12][3] = {
529 {-ICX, 0, ICZ},
530 {ICX, 0, ICZ},
531 {-ICX, 0, -ICZ},
532 {ICX, 0, -ICZ},
533 {0, ICZ, ICX},
534 {0, ICZ, -ICX},
535 {0, -ICZ, ICX},
536 {0, -ICZ, -ICX},
537 {ICZ, ICX, 0},
538 {-ICZ, ICX, 0},
539 {ICZ, -ICX, 0},
540 {-ICZ, -ICX, 0}
543 static int index[20][3] = {
544 {0, 4, 1}, {0, 9, 4},
545 {9, 5, 4}, {4, 5, 8},
546 {4, 8, 1}, {8, 10, 1},
547 {8, 3, 10}, {5, 3, 8},
548 {5, 2, 3}, {2, 7, 3},
549 {7, 10, 3}, {7, 6, 10},
550 {7, 11, 6}, {11, 0, 6},
551 {0, 1, 6}, {6, 1, 10},
552 {9, 0, 11}, {9, 11, 2},
553 {9, 2, 5}, {7, 2, 11},
556 static GLuint listnum = 0;
557 if (listnum==0) {
558 listnum = glGenLists (1);
559 glNewList (listnum,GL_COMPILE);
560 glBegin (GL_TRIANGLES);
561 for (int i=0; i<20; i++) {
562 drawPatch (&idata[index[i][2]][0],&idata[index[i][1]][0],
563 &idata[index[i][0]][0],sphere_quality);
565 glEnd();
566 glEndList();
568 glCallList (listnum);
572 static void drawSphereShadow (float px, float py, float pz, float radius)
574 // calculate shadow constants based on light vector
575 static int init=0;
576 static float len2,len1,scale;
577 if (!init) {
578 len2 = LIGHTX*LIGHTX + LIGHTY*LIGHTY;
579 len1 = 1.0f/(float)sqrt(len2);
580 scale = (float) sqrt(len2 + 1);
581 init = 1;
584 // map sphere center to ground plane based on light vector
585 px -= LIGHTX*pz;
586 py -= LIGHTY*pz;
588 const float kx = 0.96592582628907f;
589 const float ky = 0.25881904510252f;
590 float x=radius, y=0;
592 glBegin (GL_TRIANGLE_FAN);
593 for (int i=0; i<24; i++) {
594 // for all points on circle, scale to elongated rotated shadow and draw
595 float x2 = (LIGHTX*x*scale - LIGHTY*y)*len1 + px;
596 float y2 = (LIGHTY*x*scale + LIGHTX*y)*len1 + py;
597 glTexCoord2f (x2*ground_scale+ground_ofsx,y2*ground_scale+ground_ofsy);
598 glVertex3f (x2,y2,0);
600 // rotate [x,y] vector
601 float xtmp = kx*x - ky*y;
602 y = ky*x + kx*y;
603 x = xtmp;
605 glEnd();
609 static void drawTriangle (const float *v0, const float *v1, const float *v2, int solid)
611 float u[3],v[3],normal[3];
612 u[0] = v1[0] - v0[0];
613 u[1] = v1[1] - v0[1];
614 u[2] = v1[2] - v0[2];
615 v[0] = v2[0] - v0[0];
616 v[1] = v2[1] - v0[1];
617 v[2] = v2[2] - v0[2];
618 dCROSS (normal,=,u,v);
619 normalizeVector3 (normal);
621 glBegin(solid ? GL_TRIANGLES : GL_LINE_STRIP);
622 glNormal3fv (normal);
623 glVertex3fv (v0);
624 glVertex3fv (v1);
625 glVertex3fv (v2);
626 glEnd();
629 static void drawTriangleD (const double *v0, const double *v1, const double *v2, int solid)
631 float u[3],v[3],normal[3];
632 u[0] = float( v1[0] - v0[0] );
633 u[1] = float( v1[1] - v0[1] );
634 u[2] = float( v1[2] - v0[2] );
635 v[0] = float( v2[0] - v0[0] );
636 v[1] = float( v2[1] - v0[1] );
637 v[2] = float( v2[2] - v0[2] );
638 dCROSS (normal,=,u,v);
639 normalizeVector3 (normal);
641 glBegin(solid ? GL_TRIANGLES : GL_LINE_STRIP);
642 glNormal3fv (normal);
643 glVertex3dv (v0);
644 glVertex3dv (v1);
645 glVertex3dv (v2);
646 glEnd();
650 // draw a capped cylinder of length l and radius r, aligned along the x axis
652 static int capped_cylinder_quality = 3;
654 static void drawCapsule (float l, float r)
656 int i,j;
657 float tmp,nx,ny,nz,start_nx,start_ny,a,ca,sa;
658 // number of sides to the cylinder (divisible by 4):
659 const int n = capped_cylinder_quality*4;
661 l *= 0.5;
662 a = float(M_PI*2.0)/float(n);
663 sa = (float) sin(a);
664 ca = (float) cos(a);
666 // draw cylinder body
667 ny=1; nz=0; // normal vector = (0,ny,nz)
668 glBegin (GL_TRIANGLE_STRIP);
669 for (i=0; i<=n; i++) {
670 glNormal3d (ny,nz,0);
671 glVertex3d (ny*r,nz*r,l);
672 glNormal3d (ny,nz,0);
673 glVertex3d (ny*r,nz*r,-l);
674 // rotate ny,nz
675 tmp = ca*ny - sa*nz;
676 nz = sa*ny + ca*nz;
677 ny = tmp;
679 glEnd();
681 // draw first cylinder cap
682 start_nx = 0;
683 start_ny = 1;
684 for (j=0; j<(n/4); j++) {
685 // get start_n2 = rotated start_n
686 float start_nx2 = ca*start_nx + sa*start_ny;
687 float start_ny2 = -sa*start_nx + ca*start_ny;
688 // get n=start_n and n2=start_n2
689 nx = start_nx; ny = start_ny; nz = 0;
690 float nx2 = start_nx2, ny2 = start_ny2, nz2 = 0;
691 glBegin (GL_TRIANGLE_STRIP);
692 for (i=0; i<=n; i++) {
693 glNormal3d (ny2,nz2,nx2);
694 glVertex3d (ny2*r,nz2*r,l+nx2*r);
695 glNormal3d (ny,nz,nx);
696 glVertex3d (ny*r,nz*r,l+nx*r);
697 // rotate n,n2
698 tmp = ca*ny - sa*nz;
699 nz = sa*ny + ca*nz;
700 ny = tmp;
701 tmp = ca*ny2- sa*nz2;
702 nz2 = sa*ny2 + ca*nz2;
703 ny2 = tmp;
705 glEnd();
706 start_nx = start_nx2;
707 start_ny = start_ny2;
710 // draw second cylinder cap
711 start_nx = 0;
712 start_ny = 1;
713 for (j=0; j<(n/4); j++) {
714 // get start_n2 = rotated start_n
715 float start_nx2 = ca*start_nx - sa*start_ny;
716 float start_ny2 = sa*start_nx + ca*start_ny;
717 // get n=start_n and n2=start_n2
718 nx = start_nx; ny = start_ny; nz = 0;
719 float nx2 = start_nx2, ny2 = start_ny2, nz2 = 0;
720 glBegin (GL_TRIANGLE_STRIP);
721 for (i=0; i<=n; i++) {
722 glNormal3d (ny,nz,nx);
723 glVertex3d (ny*r,nz*r,-l+nx*r);
724 glNormal3d (ny2,nz2,nx2);
725 glVertex3d (ny2*r,nz2*r,-l+nx2*r);
726 // rotate n,n2
727 tmp = ca*ny - sa*nz;
728 nz = sa*ny + ca*nz;
729 ny = tmp;
730 tmp = ca*ny2- sa*nz2;
731 nz2 = sa*ny2 + ca*nz2;
732 ny2 = tmp;
734 glEnd();
735 start_nx = start_nx2;
736 start_ny = start_ny2;
741 // draw a cylinder of length l and radius r, aligned along the z axis
743 static void drawCylinder (float l, float r, float zoffset)
745 int i;
746 float tmp,ny,nz,a,ca,sa;
747 const int n = 24; // number of sides to the cylinder (divisible by 4)
749 l *= 0.5;
750 a = float(M_PI*2.0)/float(n);
751 sa = (float) sin(a);
752 ca = (float) cos(a);
754 // draw cylinder body
755 ny=1; nz=0; // normal vector = (0,ny,nz)
756 glBegin (GL_TRIANGLE_STRIP);
757 for (i=0; i<=n; i++) {
758 glNormal3d (ny,nz,0);
759 glVertex3d (ny*r,nz*r,l+zoffset);
760 glNormal3d (ny,nz,0);
761 glVertex3d (ny*r,nz*r,-l+zoffset);
762 // rotate ny,nz
763 tmp = ca*ny - sa*nz;
764 nz = sa*ny + ca*nz;
765 ny = tmp;
767 glEnd();
769 // draw top cap
770 glShadeModel (GL_FLAT);
771 ny=1; nz=0; // normal vector = (0,ny,nz)
772 glBegin (GL_TRIANGLE_FAN);
773 glNormal3d (0,0,1);
774 glVertex3d (0,0,l+zoffset);
775 for (i=0; i<=n; i++) {
776 if (i==1 || i==n/2+1)
777 setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]);
778 glNormal3d (0,0,1);
779 glVertex3d (ny*r,nz*r,l+zoffset);
780 if (i==1 || i==n/2+1)
781 setColor (color[0],color[1],color[2],color[3]);
783 // rotate ny,nz
784 tmp = ca*ny - sa*nz;
785 nz = sa*ny + ca*nz;
786 ny = tmp;
788 glEnd();
790 // draw bottom cap
791 ny=1; nz=0; // normal vector = (0,ny,nz)
792 glBegin (GL_TRIANGLE_FAN);
793 glNormal3d (0,0,-1);
794 glVertex3d (0,0,-l+zoffset);
795 for (i=0; i<=n; i++) {
796 if (i==1 || i==n/2+1)
797 setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]);
798 glNormal3d (0,0,-1);
799 glVertex3d (ny*r,nz*r,-l+zoffset);
800 if (i==1 || i==n/2+1)
801 setColor (color[0],color[1],color[2],color[3]);
803 // rotate ny,nz
804 tmp = ca*ny + sa*nz;
805 nz = -sa*ny + ca*nz;
806 ny = tmp;
808 glEnd();
811 //***************************************************************************
812 // motion model
814 // current camera position and orientation
815 static float view_xyz[3]; // position x,y,z
816 static float view_hpr[3]; // heading, pitch, roll (degrees)
819 // initialize the above variables
821 static void initMotionModel()
823 view_xyz[0] = 2;
824 view_xyz[1] = 0;
825 view_xyz[2] = 1;
826 view_hpr[0] = 180;
827 view_hpr[1] = 0;
828 view_hpr[2] = 0;
832 static void wrapCameraAngles()
834 for (int i=0; i<3; i++) {
835 while (view_hpr[i] > 180) view_hpr[i] -= 360;
836 while (view_hpr[i] < -180) view_hpr[i] += 360;
841 // call this to update the current camera position. the bits in `mode' say
842 // if the left (1), middle (2) or right (4) mouse button is pressed, and
843 // (deltax,deltay) is the amount by which the mouse pointer has moved.
845 void dsMotion (int mode, int deltax, int deltay)
847 float side = 0.01f * float(deltax);
848 float fwd = (mode==4) ? (0.01f * float(deltay)) : 0.0f;
849 float s = (float) sin (view_hpr[0]*DEG_TO_RAD);
850 float c = (float) cos (view_hpr[0]*DEG_TO_RAD);
852 if (mode==1) {
853 view_hpr[0] += float (deltax) * 0.5f;
854 view_hpr[1] += float (deltay) * 0.5f;
856 else {
857 view_xyz[0] += -s*side + c*fwd;
858 view_xyz[1] += c*side + s*fwd;
859 if (mode==2 || mode==5) view_xyz[2] += 0.01f * float(deltay);
861 wrapCameraAngles();
864 //***************************************************************************
865 // drawing loop stuff
867 // the current state:
868 // 0 = uninitialized
869 // 1 = dsSimulationLoop() called
870 // 2 = dsDrawFrame() called
871 static int current_state = 0;
873 // textures and shadows
874 static int use_textures=1; // 1 if textures to be drawn
875 static int use_shadows=1; // 1 if shadows to be drawn
876 static Texture *sky_texture = 0;
877 static Texture *ground_texture = 0;
878 static Texture *wood_texture = 0;
879 static Texture *checkered_texture = 0;
881 static Texture *texture[4+1]; // +1 since index 0 is not used
885 #if !defined(macintosh) || defined(ODE_PLATFORM_OSX)
887 void dsStartGraphics (int width, int height, dsFunctions *fn)
890 const char *prefix = DEFAULT_PATH_TO_TEXTURES;
891 if (fn->version >= 2 && fn->path_to_textures) prefix = fn->path_to_textures;
892 char *s = (char*) alloca (strlen(prefix) + 20);
894 strcpy (s,prefix);
895 strcat (s,"/sky.ppm");
896 texture[DS_SKY] = sky_texture = new Texture (s);
898 strcpy (s,prefix);
899 strcat (s,"/ground.ppm");
900 texture[DS_GROUND] = ground_texture = new Texture (s);
902 strcpy (s,prefix);
903 strcat (s,"/wood.ppm");
904 texture[DS_WOOD] = wood_texture = new Texture (s);
906 strcpy (s,prefix);
907 strcat (s,"/checkered.ppm");
908 texture[DS_CHECKERED] = checkered_texture = new Texture (s);
911 #else // macintosh
913 void dsStartGraphics (int width, int height, dsFunctions *fn)
916 // All examples build into the same dir
917 char *prefix = "::::drawstuff:textures";
918 char *s = (char*) alloca (strlen(prefix) + 20);
920 strcpy (s,prefix);
921 strcat (s,":sky.ppm");
922 sky_texture = new Texture (s);
924 strcpy (s,prefix);
925 strcat (s,":ground.ppm");
926 ground_texture = new Texture (s);
928 strcpy (s,prefix);
929 strcat (s,":wood.ppm");
930 wood_texture = new Texture (s);
933 #endif
936 void dsStopGraphics()
938 delete sky_texture;
939 delete ground_texture;
940 delete wood_texture;
941 sky_texture = 0;
942 ground_texture = 0;
943 wood_texture = 0;
947 static void drawSky (float view_xyz[3])
949 glDisable (GL_LIGHTING);
950 if (use_textures) {
951 glEnable (GL_TEXTURE_2D);
952 sky_texture->bind (0);
954 else {
955 glDisable (GL_TEXTURE_2D);
956 glColor3f (0,0.5,1.0);
959 // make sure sky depth is as far back as possible
960 glShadeModel (GL_FLAT);
961 glEnable (GL_DEPTH_TEST);
962 glDepthFunc (GL_LEQUAL);
963 glDepthRange (1,1);
965 const float ssize = 1000.0f;
966 static float offset = 0.0f;
968 float x = ssize*sky_scale;
969 float z = view_xyz[2] + sky_height;
971 glBegin (GL_QUADS);
972 glNormal3f (0,0,-1);
973 glTexCoord2f (-x+offset,-x+offset);
974 glVertex3f (-ssize+view_xyz[0],-ssize+view_xyz[1],z);
975 glTexCoord2f (-x+offset,x+offset);
976 glVertex3f (-ssize+view_xyz[0],ssize+view_xyz[1],z);
977 glTexCoord2f (x+offset,x+offset);
978 glVertex3f (ssize+view_xyz[0],ssize+view_xyz[1],z);
979 glTexCoord2f (x+offset,-x+offset);
980 glVertex3f (ssize+view_xyz[0],-ssize+view_xyz[1],z);
981 glEnd();
983 offset = offset + 0.002f;
984 if (offset > 1) offset -= 1;
986 glDepthFunc (GL_LESS);
987 glDepthRange (0,1);
991 static void drawGround()
993 glDisable (GL_LIGHTING);
994 glShadeModel (GL_FLAT);
995 glEnable (GL_DEPTH_TEST);
996 glDepthFunc (GL_LESS);
997 // glDepthRange (1,1);
999 if (use_textures) {
1000 glEnable (GL_TEXTURE_2D);
1001 ground_texture->bind (0);
1003 else {
1004 glDisable (GL_TEXTURE_2D);
1005 glColor3f (GROUND_R,GROUND_G,GROUND_B);
1008 // ground fog seems to cause problems with TNT2 under windows
1010 GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1};
1011 glEnable (GL_FOG);
1012 glFogi (GL_FOG_MODE, GL_EXP2);
1013 glFogfv (GL_FOG_COLOR, fogColor);
1014 glFogf (GL_FOG_DENSITY, 0.05f);
1015 glHint (GL_FOG_HINT, GL_NICEST); // GL_DONT_CARE);
1016 glFogf (GL_FOG_START, 1.0);
1017 glFogf (GL_FOG_END, 5.0);
1020 const float gsize = 100.0f;
1021 const float offset = 0; // -0.001f; ... polygon offsetting doesn't work well
1023 glBegin (GL_QUADS);
1024 glNormal3f (0,0,1);
1025 glTexCoord2f (-gsize*ground_scale + ground_ofsx,
1026 -gsize*ground_scale + ground_ofsy);
1027 glVertex3f (-gsize,-gsize,offset);
1028 glTexCoord2f (gsize*ground_scale + ground_ofsx,
1029 -gsize*ground_scale + ground_ofsy);
1030 glVertex3f (gsize,-gsize,offset);
1031 glTexCoord2f (gsize*ground_scale + ground_ofsx,
1032 gsize*ground_scale + ground_ofsy);
1033 glVertex3f (gsize,gsize,offset);
1034 glTexCoord2f (-gsize*ground_scale + ground_ofsx,
1035 gsize*ground_scale + ground_ofsy);
1036 glVertex3f (-gsize,gsize,offset);
1037 glEnd();
1039 glDisable (GL_FOG);
1043 static void drawPyramidGrid()
1045 // setup stuff
1046 glEnable (GL_LIGHTING);
1047 glDisable (GL_TEXTURE_2D);
1048 glShadeModel (GL_FLAT);
1049 glEnable (GL_DEPTH_TEST);
1050 glDepthFunc (GL_LESS);
1052 // draw the pyramid grid
1053 for (int i=-1; i<=1; i++) {
1054 for (int j=-1; j<=1; j++) {
1055 glPushMatrix();
1056 glTranslatef ((float)i,(float)j,(float)0);
1057 if (i==1 && j==0) setColor (1,0,0,1);
1058 else if (i==0 && j==1) setColor (0,0,1,1);
1059 else setColor (1,1,0,1);
1060 const float k = 0.03f;
1061 glBegin (GL_TRIANGLE_FAN);
1062 glNormal3f (0,-1,1);
1063 glVertex3f (0,0,k);
1064 glVertex3f (-k,-k,0);
1065 glVertex3f ( k,-k,0);
1066 glNormal3f (1,0,1);
1067 glVertex3f ( k, k,0);
1068 glNormal3f (0,1,1);
1069 glVertex3f (-k, k,0);
1070 glNormal3f (-1,0,1);
1071 glVertex3f (-k,-k,0);
1072 glEnd();
1073 glPopMatrix();
1079 void dsDrawFrame (int width, int height, dsFunctions *fn, int pause)
1081 if (current_state < 1) dsDebug ("internal error");
1082 current_state = 2;
1084 // setup stuff
1085 glEnable (GL_LIGHTING);
1086 glEnable (GL_LIGHT0);
1087 glDisable (GL_TEXTURE_2D);
1088 glDisable (GL_TEXTURE_GEN_S);
1089 glDisable (GL_TEXTURE_GEN_T);
1090 glShadeModel (GL_FLAT);
1091 glEnable (GL_DEPTH_TEST);
1092 glDepthFunc (GL_LESS);
1093 glEnable (GL_CULL_FACE);
1094 glCullFace (GL_BACK);
1095 glFrontFace (GL_CCW);
1097 // setup viewport
1098 glViewport (0,0,width,height);
1099 glMatrixMode (GL_PROJECTION);
1100 glLoadIdentity();
1101 const float vnear = 0.1f;
1102 const float vfar = 100.0f;
1103 const float k = 0.8f; // view scale, 1 = +/- 45 degrees
1104 if (width >= height) {
1105 float k2 = float(height)/float(width);
1106 glFrustum (-vnear*k,vnear*k,-vnear*k*k2,vnear*k*k2,vnear,vfar);
1108 else {
1109 float k2 = float(width)/float(height);
1110 glFrustum (-vnear*k*k2,vnear*k*k2,-vnear*k,vnear*k,vnear,vfar);
1113 // setup lights. it makes a difference whether this is done in the
1114 // GL_PROJECTION matrix mode (lights are scene relative) or the
1115 // GL_MODELVIEW matrix mode (lights are camera relative, bad!).
1116 static GLfloat light_ambient[] = { 0.5, 0.5, 0.5, 1.0 };
1117 static GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
1118 static GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
1119 glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient);
1120 glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse);
1121 glLightfv (GL_LIGHT0, GL_SPECULAR, light_specular);
1122 glColor3f (1.0, 1.0, 1.0);
1124 // clear the window
1125 glClearColor (0.5,0.5,0.5,0);
1126 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1128 // snapshot camera position (in MS Windows it is changed by the GUI thread)
1129 float view2_xyz[3];
1130 float view2_hpr[3];
1131 memcpy (view2_xyz,view_xyz,sizeof(float)*3);
1132 memcpy (view2_hpr,view_hpr,sizeof(float)*3);
1134 // go to GL_MODELVIEW matrix mode and set the camera
1135 glMatrixMode (GL_MODELVIEW);
1136 glLoadIdentity();
1137 setCamera (view2_xyz[0],view2_xyz[1],view2_xyz[2],
1138 view2_hpr[0],view2_hpr[1],view2_hpr[2]);
1140 // set the light position (for some reason we have to do this in model view.
1141 static GLfloat light_position[] = { LIGHTX, LIGHTY, 1.0, 0.0 };
1142 glLightfv (GL_LIGHT0, GL_POSITION, light_position);
1144 // draw the background (ground, sky etc)
1145 drawSky (view2_xyz);
1146 drawGround();
1148 // draw the little markers on the ground
1149 drawPyramidGrid();
1151 // leave openGL in a known state - flat shaded white, no textures
1152 glEnable (GL_LIGHTING);
1153 glDisable (GL_TEXTURE_2D);
1154 glShadeModel (GL_FLAT);
1155 glEnable (GL_DEPTH_TEST);
1156 glDepthFunc (GL_LESS);
1157 glColor3f (1,1,1);
1158 setColor (1,1,1,1);
1160 // draw the rest of the objects. set drawing state first.
1161 color[0] = 1;
1162 color[1] = 1;
1163 color[2] = 1;
1164 color[3] = 1;
1165 tnum = 0;
1166 if (fn->step) fn->step (pause);
1170 int dsGetShadows()
1172 return use_shadows;
1176 void dsSetShadows (int a)
1178 use_shadows = (a != 0);
1182 int dsGetTextures()
1184 return use_textures;
1188 void dsSetTextures (int a)
1190 use_textures = (a != 0);
1193 //***************************************************************************
1194 // C interface
1196 // sets lighting and texture modes, sets current color
1197 static void setupDrawingMode()
1199 glEnable (GL_LIGHTING);
1200 if (tnum) {
1201 if (use_textures) {
1202 glEnable (GL_TEXTURE_2D);
1203 texture[tnum]->bind (1);
1204 glEnable (GL_TEXTURE_GEN_S);
1205 glEnable (GL_TEXTURE_GEN_T);
1206 glTexGeni (GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
1207 glTexGeni (GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
1208 static GLfloat s_params[4] = {1.0f,1.0f,0.0f,1};
1209 static GLfloat t_params[4] = {0.817f,-0.817f,0.817f,1};
1210 glTexGenfv (GL_S,GL_OBJECT_PLANE,s_params);
1211 glTexGenfv (GL_T,GL_OBJECT_PLANE,t_params);
1213 else {
1214 glDisable (GL_TEXTURE_2D);
1217 else {
1218 glDisable (GL_TEXTURE_2D);
1220 setColor (color[0],color[1],color[2],color[3]);
1222 if (color[3] < 1) {
1223 glEnable (GL_BLEND);
1224 glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1226 else {
1227 glDisable (GL_BLEND);
1232 static void setShadowDrawingMode()
1234 glDisable (GL_LIGHTING);
1235 if (use_textures) {
1236 glEnable (GL_TEXTURE_2D);
1237 ground_texture->bind (1);
1238 glColor3f (SHADOW_INTENSITY,SHADOW_INTENSITY,SHADOW_INTENSITY);
1239 glEnable (GL_TEXTURE_2D);
1240 glEnable (GL_TEXTURE_GEN_S);
1241 glEnable (GL_TEXTURE_GEN_T);
1242 glTexGeni (GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
1243 glTexGeni (GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
1244 static GLfloat s_params[4] = {ground_scale,0,0,ground_ofsx};
1245 static GLfloat t_params[4] = {0,ground_scale,0,ground_ofsy};
1246 glTexGenfv (GL_S,GL_EYE_PLANE,s_params);
1247 glTexGenfv (GL_T,GL_EYE_PLANE,t_params);
1249 else {
1250 glDisable (GL_TEXTURE_2D);
1251 glColor3f (GROUND_R*SHADOW_INTENSITY,GROUND_G*SHADOW_INTENSITY,
1252 GROUND_B*SHADOW_INTENSITY);
1254 glDepthRange (0,0.9999);
1258 extern "C" void dsSimulationLoop (int argc, char **argv,
1259 int window_width, int window_height,
1260 dsFunctions *fn)
1262 if (current_state != 0) dsError ("dsSimulationLoop() called more than once");
1263 current_state = 1;
1265 // look for flags that apply to us
1266 int initial_pause = 0;
1267 for (int i=1; i<argc; i++) {
1268 if (strcmp(argv[i],"-notex")==0) use_textures = 0;
1269 if (strcmp(argv[i],"-noshadow")==0) use_shadows = 0;
1270 if (strcmp(argv[i],"-noshadows")==0) use_shadows = 0;
1271 if (strcmp(argv[i],"-pause")==0) initial_pause = 1;
1272 if (strcmp(argv[i],"-texturepath")==0)
1273 if (++i < argc)
1274 fn->path_to_textures = argv[i];
1277 if (fn->version > DS_VERSION)
1278 dsDebug ("bad version number in dsFunctions structure");
1280 initMotionModel();
1281 dsPlatformSimLoop (window_width,window_height,fn,initial_pause);
1283 current_state = 0;
1287 extern "C" void dsSetViewpoint (float xyz[3], float hpr[3])
1289 if (current_state < 1) dsError ("dsSetViewpoint() called before simulation started");
1290 if (xyz) {
1291 view_xyz[0] = xyz[0];
1292 view_xyz[1] = xyz[1];
1293 view_xyz[2] = xyz[2];
1295 if (hpr) {
1296 view_hpr[0] = hpr[0];
1297 view_hpr[1] = hpr[1];
1298 view_hpr[2] = hpr[2];
1299 wrapCameraAngles();
1304 extern "C" void dsGetViewpoint (float xyz[3], float hpr[3])
1306 if (current_state < 1) dsError ("dsGetViewpoint() called before simulation started");
1307 if (xyz) {
1308 xyz[0] = view_xyz[0];
1309 xyz[1] = view_xyz[1];
1310 xyz[2] = view_xyz[2];
1312 if (hpr) {
1313 hpr[0] = view_hpr[0];
1314 hpr[1] = view_hpr[1];
1315 hpr[2] = view_hpr[2];
1320 extern "C" void dsSetTexture (int texture_number)
1322 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1323 tnum = texture_number;
1327 extern "C" void dsSetColor (float red, float green, float blue)
1329 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1330 color[0] = red;
1331 color[1] = green;
1332 color[2] = blue;
1333 color[3] = 1;
1337 extern "C" void dsSetColorAlpha (float red, float green, float blue,
1338 float alpha)
1340 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1341 color[0] = red;
1342 color[1] = green;
1343 color[2] = blue;
1344 color[3] = alpha;
1348 extern "C" void dsDrawBox (const float pos[3], const float R[12],
1349 const float sides[3])
1351 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1352 setupDrawingMode();
1353 glShadeModel (GL_FLAT);
1354 setTransform (pos,R);
1355 drawBox (sides);
1356 glPopMatrix();
1358 if (use_shadows) {
1359 setShadowDrawingMode();
1360 setShadowTransform();
1361 setTransform (pos,R);
1362 drawBox (sides);
1363 glPopMatrix();
1364 glPopMatrix();
1365 glDepthRange (0,1);
1369 extern "C" void dsDrawConvex (const float pos[3], const float R[12],
1370 float *_planes,unsigned int _planecount,
1371 float *_points,
1372 unsigned int _pointcount,
1373 unsigned int *_polygons)
1375 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1376 setupDrawingMode();
1377 glShadeModel (GL_FLAT);
1378 setTransform (pos,R);
1379 drawConvex(_planes,_planecount,_points,_pointcount,_polygons);
1380 glPopMatrix();
1381 if (use_shadows) {
1382 setShadowDrawingMode();
1383 setShadowTransform();
1384 setTransform (pos,R);
1385 drawConvex(_planes,_planecount,_points,_pointcount,_polygons);
1386 glPopMatrix();
1387 glPopMatrix();
1388 glDepthRange (0,1);
1393 extern "C" void dsDrawSphere (const float pos[3], const float R[12],
1394 float radius)
1396 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1397 setupDrawingMode();
1398 glEnable (GL_NORMALIZE);
1399 glShadeModel (GL_SMOOTH);
1400 setTransform (pos,R);
1401 glScaled (radius,radius,radius);
1402 drawSphere();
1403 glPopMatrix();
1404 glDisable (GL_NORMALIZE);
1406 // draw shadows
1407 if (use_shadows) {
1408 glDisable (GL_LIGHTING);
1409 if (use_textures) {
1410 ground_texture->bind (1);
1411 glEnable (GL_TEXTURE_2D);
1412 glDisable (GL_TEXTURE_GEN_S);
1413 glDisable (GL_TEXTURE_GEN_T);
1414 glColor3f (SHADOW_INTENSITY,SHADOW_INTENSITY,SHADOW_INTENSITY);
1416 else {
1417 glDisable (GL_TEXTURE_2D);
1418 glColor3f (GROUND_R*SHADOW_INTENSITY,GROUND_G*SHADOW_INTENSITY,
1419 GROUND_B*SHADOW_INTENSITY);
1421 glShadeModel (GL_FLAT);
1422 glDepthRange (0,0.9999);
1423 drawSphereShadow (pos[0],pos[1],pos[2],radius);
1424 glDepthRange (0,1);
1429 extern "C" void dsDrawTriangle (const float pos[3], const float R[12],
1430 const float *v0, const float *v1,
1431 const float *v2, int solid)
1433 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1434 setupDrawingMode();
1435 glShadeModel (GL_FLAT);
1436 setTransform (pos,R);
1437 drawTriangle (v0, v1, v2, solid);
1438 glPopMatrix();
1442 extern "C" void dsDrawCylinder (const float pos[3], const float R[12],
1443 float length, float radius)
1445 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1446 setupDrawingMode();
1447 glShadeModel (GL_SMOOTH);
1448 setTransform (pos,R);
1449 drawCylinder (length,radius,0);
1450 glPopMatrix();
1452 if (use_shadows) {
1453 setShadowDrawingMode();
1454 setShadowTransform();
1455 setTransform (pos,R);
1456 drawCylinder (length,radius,0);
1457 glPopMatrix();
1458 glPopMatrix();
1459 glDepthRange (0,1);
1464 extern "C" void dsDrawCapsule (const float pos[3], const float R[12],
1465 float length, float radius)
1467 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1468 setupDrawingMode();
1469 glShadeModel (GL_SMOOTH);
1470 setTransform (pos,R);
1471 drawCapsule (length,radius);
1472 glPopMatrix();
1474 if (use_shadows) {
1475 setShadowDrawingMode();
1476 setShadowTransform();
1477 setTransform (pos,R);
1478 drawCapsule (length,radius);
1479 glPopMatrix();
1480 glPopMatrix();
1481 glDepthRange (0,1);
1486 void dsDrawLine (const float pos1[3], const float pos2[3])
1488 setupDrawingMode();
1489 glColor3f (color[0],color[1],color[2]);
1490 glDisable (GL_LIGHTING);
1491 glLineWidth (2);
1492 glShadeModel (GL_FLAT);
1493 glBegin (GL_LINES);
1494 glVertex3f (pos1[0],pos1[1],pos1[2]);
1495 glVertex3f (pos2[0],pos2[1],pos2[2]);
1496 glEnd();
1500 void dsDrawBoxD (const double pos[3], const double R[12],
1501 const double sides[3])
1503 int i;
1504 float pos2[3],R2[12],fsides[3];
1505 for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1506 for (i=0; i<12; i++) R2[i]=(float)R[i];
1507 for (i=0; i<3; i++) fsides[i]=(float)sides[i];
1508 dsDrawBox (pos2,R2,fsides);
1511 extern "C" void dsDrawConvexD (const double pos[3], const double R[12],
1512 double *_planes,unsigned int _planecount,
1513 double *_points,
1514 unsigned int _pointcount,
1515 unsigned int *_polygons)
1517 if (current_state != 2) dsError ("drawing function called outside simulation loop");
1518 setupDrawingMode();
1519 glShadeModel (GL_FLAT);
1520 setTransformD (pos,R);
1521 drawConvexD(_planes,_planecount,_points,_pointcount,_polygons);
1522 glPopMatrix();
1523 if (use_shadows) {
1524 setShadowDrawingMode();
1525 setShadowTransform();
1526 setTransformD (pos,R);
1527 drawConvexD(_planes,_planecount,_points,_pointcount,_polygons);
1528 glPopMatrix();
1529 glPopMatrix();
1530 glDepthRange (0,1);
1534 void dsDrawSphereD (const double pos[3], const double R[12], float radius)
1536 int i;
1537 float pos2[3],R2[12];
1538 for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1539 for (i=0; i<12; i++) R2[i]=(float)R[i];
1540 dsDrawSphere (pos2,R2,radius);
1544 void dsDrawTriangleD (const double pos[3], const double R[12],
1545 const double *v0, const double *v1,
1546 const double *v2, int solid)
1548 int i;
1549 float pos2[3],R2[12];
1550 for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1551 for (i=0; i<12; i++) R2[i]=(float)R[i];
1553 setupDrawingMode();
1554 glShadeModel (GL_FLAT);
1555 setTransform (pos2,R2);
1556 drawTriangleD (v0, v1, v2, solid);
1557 glPopMatrix();
1561 void dsDrawCylinderD (const double pos[3], const double R[12],
1562 float length, float radius)
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 dsDrawCylinder (pos2,R2,length,radius);
1572 void dsDrawCapsuleD (const double pos[3], const double R[12],
1573 float length, float radius)
1575 int i;
1576 float pos2[3],R2[12];
1577 for (i=0; i<3; i++) pos2[i]=(float)pos[i];
1578 for (i=0; i<12; i++) R2[i]=(float)R[i];
1579 dsDrawCapsule (pos2,R2,length,radius);
1583 void dsDrawLineD (const double _pos1[3], const double _pos2[3])
1585 int i;
1586 float pos1[3],pos2[3];
1587 for (i=0; i<3; i++) pos1[i]=(float)_pos1[i];
1588 for (i=0; i<3; i++) pos2[i]=(float)_pos2[i];
1589 dsDrawLine (pos1,pos2);
1593 void dsSetSphereQuality (int n)
1595 sphere_quality = n;
1599 void dsSetCapsuleQuality (int n)
1601 capped_cylinder_quality = n;
1604 void dsSetDrawMode(int mode)
1606 switch(mode)
1608 case DS_POLYFILL:
1609 glPolygonMode(GL_FRONT,GL_FILL);
1610 break;
1611 case DS_WIREFRAME:
1612 glPolygonMode(GL_FRONT,GL_LINE);
1613 break;