1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
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 *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
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. *
21 *************************************************************************/
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
36 manage openGL state changes better
46 #ifdef HAVE_APPLE_OPENGL_FRAMEWORK
47 #include <OpenGL/gl.h>
48 #include <OpenGL/glu.h>
54 #include "drawstuff/drawstuff.h"
57 //***************************************************************************
60 #ifndef DEFAULT_PATH_TO_TEXTURES
62 #define DEFAULT_PATH_TO_TEXTURES "..\\textures\\"
64 #define DEFAULT_PATH_TO_TEXTURES "../textures/"
69 #define M_PI (3.14159265358979323846)
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
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];
104 len
= 1.0f
/ (float)sqrt(len
);
111 //***************************************************************************
114 typedef unsigned char byte
;
117 int image_width
,image_height
;
120 Image (char *filename
);
121 // load from PPM file
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
)
136 if (c
==EOF
) dsError ("unexpected end of file in \"%s\"",filename
);
142 if (d
==EOF
) dsError ("unexpected end of file in \"%s\"",filename
);
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
)
163 if (c
==EOF
) dsError ("unexpected end of file in \"%s\"",filename
);
164 if (c
>= '0' && c
<= '9') n
= n
*10 + (c
- '0');
173 Image::Image (char *filename
)
175 FILE *f
= fopen (filename
,"rb");
176 if (!f
) dsError ("Can't open image file `%s'",filename
);
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
);
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)
204 if (c
!= 10) 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
);
221 //***************************************************************************
228 Texture (char *filename
);
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
);
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
);
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])
344 glMultMatrixf (matrix
);
346 static void setTransformD (const double pos
[3], const double R
[12])
366 glMultMatrixd (matrix
);
370 // set shadow projection transform
372 static void setShadowTransform()
375 for (int i
=0; i
<16; i
++) matrix
[i
] = 0;
382 glMultMatrixf (matrix
);
385 static void drawConvex (float *_planes
,unsigned int _planecount
,
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
];
395 glBegin (GL_POLYGON
);
396 glNormal3f(_planes
[(i
*4)+0],
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]);
410 static void drawConvexD (double *_planes
,unsigned int _planecount
,
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
];
420 glBegin (GL_POLYGON
);
421 glNormal3d(_planes
[(i
*4)+0],
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]);
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
;
442 glBegin (GL_TRIANGLE_STRIP
);
444 glVertex3f (-lx
,-ly
,-lz
);
445 glVertex3f (-lx
,-ly
,lz
);
446 glVertex3f (-lx
,ly
,-lz
);
447 glVertex3f (-lx
,ly
,lz
);
449 glVertex3f (lx
,ly
,-lz
);
450 glVertex3f (lx
,ly
,lz
);
452 glVertex3f (lx
,-ly
,-lz
);
453 glVertex3f (lx
,-ly
,lz
);
455 glVertex3f (-lx
,-ly
,-lz
);
456 glVertex3f (-lx
,-ly
,lz
);
460 glBegin (GL_TRIANGLE_FAN
);
462 glVertex3f (-lx
,-ly
,lz
);
463 glVertex3f (lx
,-ly
,lz
);
464 glVertex3f (lx
,ly
,lz
);
465 glVertex3f (-lx
,ly
,lz
);
469 glBegin (GL_TRIANGLE_FAN
);
471 glVertex3f (-lx
,-ly
,-lz
);
472 glVertex3f (-lx
,ly
,-lz
);
473 glVertex3f (lx
,ly
,-lz
);
474 glVertex3f (lx
,-ly
,-lz
);
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
)
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
++) {
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);
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] = {
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;
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
);
568 glCallList (listnum
);
572 static void drawSphereShadow (float px
, float py
, float pz
, float radius
)
574 // calculate shadow constants based on light vector
576 static float len2
,len1
,scale
;
578 len2
= LIGHTX
*LIGHTX
+ LIGHTY
*LIGHTY
;
579 len1
= 1.0f
/(float)sqrt(len2
);
580 scale
= (float) sqrt(len2
+ 1);
584 // map sphere center to ground plane based on light vector
588 const float kx
= 0.96592582628907f
;
589 const float ky
= 0.25881904510252f
;
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
;
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
);
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
);
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
)
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;
662 a
= float(M_PI
*2.0)/float(n
);
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
);
681 // draw first cylinder cap
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
);
701 tmp
= ca
*ny2
- sa
*nz2
;
702 nz2
= sa
*ny2
+ ca
*nz2
;
706 start_nx
= start_nx2
;
707 start_ny
= start_ny2
;
710 // draw second cylinder cap
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
);
730 tmp
= ca
*ny2
- sa
*nz2
;
731 nz2
= sa
*ny2
+ ca
*nz2
;
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
)
746 float tmp
,ny
,nz
,a
,ca
,sa
;
747 const int n
= 24; // number of sides to the cylinder (divisible by 4)
750 a
= float(M_PI
*2.0)/float(n
);
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
);
770 glShadeModel (GL_FLAT
);
771 ny
=1; nz
=0; // normal vector = (0,ny,nz)
772 glBegin (GL_TRIANGLE_FAN
);
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]);
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]);
791 ny
=1; nz
=0; // normal vector = (0,ny,nz)
792 glBegin (GL_TRIANGLE_FAN
);
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]);
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]);
811 //***************************************************************************
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()
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
);
853 view_hpr
[0] += float (deltax
) * 0.5f
;
854 view_hpr
[1] += float (deltay
) * 0.5f
;
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
);
864 //***************************************************************************
865 // drawing loop stuff
867 // the current state:
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);
895 strcat (s
,"/sky.ppm");
896 texture
[DS_SKY
] = sky_texture
= new Texture (s
);
899 strcat (s
,"/ground.ppm");
900 texture
[DS_GROUND
] = ground_texture
= new Texture (s
);
903 strcat (s
,"/wood.ppm");
904 texture
[DS_WOOD
] = wood_texture
= new Texture (s
);
907 strcat (s
,"/checkered.ppm");
908 texture
[DS_CHECKERED
] = checkered_texture
= new Texture (s
);
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);
921 strcat (s
,":sky.ppm");
922 sky_texture
= new Texture (s
);
925 strcat (s
,":ground.ppm");
926 ground_texture
= new Texture (s
);
929 strcat (s
,":wood.ppm");
930 wood_texture
= new Texture (s
);
936 void dsStopGraphics()
939 delete ground_texture
;
947 static void drawSky (float view_xyz
[3])
949 glDisable (GL_LIGHTING
);
951 glEnable (GL_TEXTURE_2D
);
952 sky_texture
->bind (0);
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
);
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
;
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
);
983 offset
= offset
+ 0.002f
;
984 if (offset
> 1) offset
-= 1;
986 glDepthFunc (GL_LESS
);
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);
1000 glEnable (GL_TEXTURE_2D
);
1001 ground_texture
->bind (0);
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};
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
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
);
1043 static void drawPyramidGrid()
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
++) {
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);
1064 glVertex3f (-k
,-k
,0);
1065 glVertex3f ( k
,-k
,0);
1067 glVertex3f ( k
, k
,0);
1069 glVertex3f (-k
, k
,0);
1070 glNormal3f (-1,0,1);
1071 glVertex3f (-k
,-k
,0);
1079 void dsDrawFrame (int width
, int height
, dsFunctions
*fn
, int pause
)
1081 if (current_state
< 1) dsDebug ("internal error");
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
);
1098 glViewport (0,0,width
,height
);
1099 glMatrixMode (GL_PROJECTION
);
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
);
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);
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)
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
);
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
);
1148 // draw the little markers on the ground
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
);
1160 // draw the rest of the objects. set drawing state first.
1166 if (fn
->step
) fn
->step (pause
);
1176 void dsSetShadows (int a
)
1178 use_shadows
= (a
!= 0);
1184 return use_textures
;
1188 void dsSetTextures (int a
)
1190 use_textures
= (a
!= 0);
1193 //***************************************************************************
1196 // sets lighting and texture modes, sets current color
1197 static void setupDrawingMode()
1199 glEnable (GL_LIGHTING
);
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
);
1214 glDisable (GL_TEXTURE_2D
);
1218 glDisable (GL_TEXTURE_2D
);
1220 setColor (color
[0],color
[1],color
[2],color
[3]);
1223 glEnable (GL_BLEND
);
1224 glBlendFunc (GL_SRC_ALPHA
,GL_ONE_MINUS_SRC_ALPHA
);
1227 glDisable (GL_BLEND
);
1232 static void setShadowDrawingMode()
1234 glDisable (GL_LIGHTING
);
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
);
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
,
1262 if (current_state
!= 0) dsError ("dsSimulationLoop() called more than once");
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)
1274 fn
->path_to_textures
= argv
[i
];
1277 if (fn
->version
> DS_VERSION
)
1278 dsDebug ("bad version number in dsFunctions structure");
1281 dsPlatformSimLoop (window_width
,window_height
,fn
,initial_pause
);
1287 extern "C" void dsSetViewpoint (float xyz
[3], float hpr
[3])
1289 if (current_state
< 1) dsError ("dsSetViewpoint() called before simulation started");
1291 view_xyz
[0] = xyz
[0];
1292 view_xyz
[1] = xyz
[1];
1293 view_xyz
[2] = xyz
[2];
1296 view_hpr
[0] = hpr
[0];
1297 view_hpr
[1] = hpr
[1];
1298 view_hpr
[2] = hpr
[2];
1304 extern "C" void dsGetViewpoint (float xyz
[3], float hpr
[3])
1306 if (current_state
< 1) dsError ("dsGetViewpoint() called before simulation started");
1308 xyz
[0] = view_xyz
[0];
1309 xyz
[1] = view_xyz
[1];
1310 xyz
[2] = view_xyz
[2];
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");
1337 extern "C" void dsSetColorAlpha (float red
, float green
, float blue
,
1340 if (current_state
!= 2) dsError ("drawing function called outside simulation loop");
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");
1353 glShadeModel (GL_FLAT
);
1354 setTransform (pos
,R
);
1359 setShadowDrawingMode();
1360 setShadowTransform();
1361 setTransform (pos
,R
);
1369 extern "C" void dsDrawConvex (const float pos
[3], const float R
[12],
1370 float *_planes
,unsigned int _planecount
,
1372 unsigned int _pointcount
,
1373 unsigned int *_polygons
)
1375 if (current_state
!= 2) dsError ("drawing function called outside simulation loop");
1377 glShadeModel (GL_FLAT
);
1378 setTransform (pos
,R
);
1379 drawConvex(_planes
,_planecount
,_points
,_pointcount
,_polygons
);
1382 setShadowDrawingMode();
1383 setShadowTransform();
1384 setTransform (pos
,R
);
1385 drawConvex(_planes
,_planecount
,_points
,_pointcount
,_polygons
);
1393 extern "C" void dsDrawSphere (const float pos
[3], const float R
[12],
1396 if (current_state
!= 2) dsError ("drawing function called outside simulation loop");
1398 glEnable (GL_NORMALIZE
);
1399 glShadeModel (GL_SMOOTH
);
1400 setTransform (pos
,R
);
1401 glScaled (radius
,radius
,radius
);
1404 glDisable (GL_NORMALIZE
);
1408 glDisable (GL_LIGHTING
);
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
);
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
);
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");
1435 glShadeModel (GL_FLAT
);
1436 setTransform (pos
,R
);
1437 drawTriangle (v0
, v1
, v2
, solid
);
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");
1447 glShadeModel (GL_SMOOTH
);
1448 setTransform (pos
,R
);
1449 drawCylinder (length
,radius
,0);
1453 setShadowDrawingMode();
1454 setShadowTransform();
1455 setTransform (pos
,R
);
1456 drawCylinder (length
,radius
,0);
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");
1469 glShadeModel (GL_SMOOTH
);
1470 setTransform (pos
,R
);
1471 drawCapsule (length
,radius
);
1475 setShadowDrawingMode();
1476 setShadowTransform();
1477 setTransform (pos
,R
);
1478 drawCapsule (length
,radius
);
1486 void dsDrawLine (const float pos1
[3], const float pos2
[3])
1489 glColor3f (color
[0],color
[1],color
[2]);
1490 glDisable (GL_LIGHTING
);
1492 glShadeModel (GL_FLAT
);
1494 glVertex3f (pos1
[0],pos1
[1],pos1
[2]);
1495 glVertex3f (pos2
[0],pos2
[1],pos2
[2]);
1500 void dsDrawBoxD (const double pos
[3], const double R
[12],
1501 const double sides
[3])
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
,
1514 unsigned int _pointcount
,
1515 unsigned int *_polygons
)
1517 if (current_state
!= 2) dsError ("drawing function called outside simulation loop");
1519 glShadeModel (GL_FLAT
);
1520 setTransformD (pos
,R
);
1521 drawConvexD(_planes
,_planecount
,_points
,_pointcount
,_polygons
);
1524 setShadowDrawingMode();
1525 setShadowTransform();
1526 setTransformD (pos
,R
);
1527 drawConvexD(_planes
,_planecount
,_points
,_pointcount
,_polygons
);
1534 void dsDrawSphereD (const double pos
[3], const double R
[12], float radius
)
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
)
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
];
1554 glShadeModel (GL_FLAT
);
1555 setTransform (pos2
,R2
);
1556 drawTriangleD (v0
, v1
, v2
, solid
);
1561 void dsDrawCylinderD (const double pos
[3], const double R
[12],
1562 float length
, float radius
)
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
)
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])
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
)
1599 void dsSetCapsuleQuality (int n
)
1601 capped_cylinder_quality
= n
;
1604 void dsSetDrawMode(int mode
)
1609 glPolygonMode(GL_FRONT
,GL_FILL
);
1612 glPolygonMode(GL_FRONT
,GL_LINE
);