All changes are from John, except for:
[freeglut] / src / freeglut_geometry.c
1 /*
2  * freeglut_geometry.c
3  *
4  * Freeglut geometry rendering methods.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Fri Dec 3 1999
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "../include/GL/freeglut.h"
33 #include "freeglut_internal.h"
34
35 /*
36  * TODO BEFORE THE STABLE RELEASE:
37  *
38  * Following functions have been contributed by Andreas Umbach.
39  *
40  *      glutWireCube()          -- looks OK
41  *      glutSolidCube()         -- OK
42  *      glutWireSphere()        -- OK
43  *      glutSolidSphere()       -- OK
44  *
45  * Following functions have been implemented by Pawel and modified by John Fay:
46  *
47  *      glutWireCone()          -- looks OK
48  *      glutSolidCone()         -- looks OK
49  *
50  * Those functions have been implemented by John Fay.
51  *
52  *      glutWireTorus()         -- looks OK
53  *      glutSolidTorus()        -- looks OK
54  *      glutWireDodecahedron()  -- looks OK
55  *      glutSolidDodecahedron() -- looks OK
56  *      glutWireOctahedron()    -- looks OK
57  *      glutSolidOctahedron()   -- looks OK
58  *      glutWireTetrahedron()   -- looks OK
59  *      glutSolidTetrahedron()  -- looks OK
60  *      glutWireIcosahedron()   -- looks OK
61  *      glutSolidIcosahedron()  -- looks OK
62  */
63
64
65 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
66
67 /*
68  * Draws a wireframed cube. Code contributed by Andreas Umbach <marvin@dataway.ch>
69  */
70 void FGAPIENTRY glutWireCube( GLdouble dSize )
71 {
72     double size = dSize * 0.5;
73
74 #   define V(a,b,c) glVertex3d( a size, b size, c size );
75 #   define N(a,b,c) glNormal3d( a, b, c );
76
77     /*
78      * PWO: I dared to convert the code to use macros...
79      */
80     glBegin( GL_LINE_LOOP ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); glEnd();
81     glBegin( GL_LINE_LOOP ); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); glEnd();
82     glBegin( GL_LINE_LOOP ); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); glEnd();
83     glBegin( GL_LINE_LOOP ); N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); glEnd();
84     glBegin( GL_LINE_LOOP ); N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); glEnd();
85     glBegin( GL_LINE_LOOP ); N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); glEnd();
86
87 #   undef V
88 #   undef N
89 }
90
91 /*
92  * Draws a solid cube. Code contributed by Andreas Umbach <marvin@dataway.ch>
93  */
94 void FGAPIENTRY glutSolidCube( GLdouble dSize )
95 {
96     double size = dSize * 0.5;
97
98 #   define V(a,b,c) glVertex3d( a size, b size, c size );
99 #   define N(a,b,c) glNormal3d( a, b, c );
100
101     /*
102      * PWO: Again, I dared to convert the code to use macros...
103      */
104     glBegin( GL_QUADS );
105         N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+);
106         N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+);
107         N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+);
108         N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-);
109         N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+);
110         N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-);
111     glEnd();
112
113 #   undef V
114 #   undef N
115 }
116
117 /*
118  * Draws a wire sphere. Code contributed by Andreas Umbach <marvin@dataway.ch>
119  */
120 void FGAPIENTRY glutWireSphere( GLdouble dRadius, GLint slices, GLint stacks )
121 {
122     double  radius = dRadius, phi, psi, dpsi, dphi;
123     double *vertex;
124     int    i, j;
125     double cphi, sphi, cpsi, spsi ;
126
127     /*
128      * Allocate the vertices array
129      */
130     vertex = (double *)calloc( sizeof(double), 3 * slices * (stacks - 1) );
131
132     glPushMatrix();
133     glScaled( radius, radius, radius );
134
135     dpsi = M_PI / (stacks + 1);
136     dphi = 2 * M_PI / slices;
137     psi  = dpsi;
138
139     for( j=0; j<stacks-1; j++ )
140     {
141         cpsi = cos ( psi ) ;
142         spsi = sin ( psi ) ;
143         phi = 0.0;
144
145         for( i=0; i<slices; i++ )
146         {
147           int offset = 3 * ( j * slices + i ) ;
148           cphi = cos ( phi ) ;
149           sphi = sin ( phi ) ;
150             *(vertex + offset + 0) = sphi * spsi ;
151             *(vertex + offset + 1) = cphi * spsi ;
152             *(vertex + offset + 2) = cpsi ;
153             phi += dphi;
154         }
155
156         psi += dpsi;
157     }
158
159     for( i=0; i<slices; i++ )
160     {
161         glBegin( GL_LINE_STRIP );
162         glNormal3d( 0, 0, 1 );
163         glVertex3d( 0, 0, 1 );
164
165         for( j=0; j<stacks - 1; j++ )
166         {
167           int offset = 3 * ( j * slices + i ) ;
168             glNormal3dv( vertex + offset );
169             glVertex3dv( vertex + offset );
170         }
171
172         glNormal3d(0, 0, -1);
173         glVertex3d(0, 0, -1);
174         glEnd();
175     }
176
177     for( j=0; j<stacks-1; j++ )
178     {
179         glBegin(GL_LINE_LOOP);
180
181         for( i=0; i<slices; i++ )
182         {
183           int offset = 3 * ( j * slices + i ) ;
184             glNormal3dv( vertex + offset );
185             glVertex3dv( vertex + offset );
186         }
187
188         glEnd();
189     }
190
191     free( vertex );
192     glPopMatrix();
193 }
194
195 /*
196  * Draws a solid sphere. Code contributed by Andreas Umbach <marvin@dataway.ch>
197  */
198 void FGAPIENTRY glutSolidSphere( GLdouble dRadius, GLint slices, GLint stacks )
199 {
200     double  radius = dRadius, phi, psi, dpsi, dphi;
201     double *next, *tmp, *row;
202     int    i, j;
203     double cphi, sphi, cpsi, spsi ;
204
205     glPushMatrix();
206     /* glScalef( radius, radius, radius ); */
207
208     row  = (double *)calloc( sizeof(double), slices * 3 );
209     next = (double *)calloc( sizeof(double), slices * 3 );
210
211     dpsi = M_PI / (stacks + 1);
212     dphi = 2 * M_PI / slices;
213     psi  = dpsi;
214     phi  = 0;
215
216     /* init first line + do polar cap */
217     glBegin( GL_TRIANGLE_FAN );
218     glNormal3d( 0.0, 0.0, 1.0 );
219     glVertex3d( 0.0, 0.0, radius );
220
221     for( i=0; i<slices; i++ )
222     {
223         row[ i * 3 + 0 ] = sin( phi ) * sin( psi );
224         row[ i * 3 + 1 ] = cos( phi ) * sin( psi );
225         row[ i * 3 + 2 ] = cos( psi );
226
227         glNormal3dv( row + 3 * i );
228         glVertex3d(
229             radius * *(row + 3 * i + 0),
230             radius * *(row + 3 * i + 1),
231                   radius * *(row + 3 * i + 2)
232             );
233         
234         phi += dphi;
235     }
236
237     glNormal3dv( row );
238     glVertex3d( radius * *(row + 0), radius * *(row + 1), radius * *(row + 2) );
239     glEnd();
240
241     for( j=0; j<stacks-1; j++ )
242     {
243         phi = 0.0;
244         psi += dpsi;
245         cpsi = cos ( psi ) ;
246         spsi = sin ( psi ) ;
247
248         /* get coords */
249         glBegin( GL_QUAD_STRIP );
250
251         /* glBegin(GL_LINE_LOOP); */
252         for( i=0; i<slices; i++ )
253         {
254           cphi = cos ( phi ) ;
255           sphi = sin ( phi ) ;
256             next[ i * 3 + 0 ] = sphi * spsi ;
257             next[ i * 3 + 1 ] = cphi * spsi ;
258             next[ i * 3 + 2 ] = cpsi ;
259
260             glNormal3dv( row + i * 3 );
261             glVertex3d(
262                 radius * *(row + 3 * i + 0),
263                 radius * *(row + 3 * i + 1),
264                         radius * *(row + 3 * i + 2)
265                     );
266
267             glNormal3dv( next + i * 3 );
268             glVertex3d(
269                 radius * *(next + 3 * i + 0),
270                 radius * *(next + 3 * i + 1),
271                 radius * *(next + 3 * i + 2)
272             );
273
274             phi += dphi;
275         }
276
277         glNormal3dv( row );
278         glVertex3d( radius * *(row + 0), radius * *(row + 1), radius * *(row + 2) );
279         glNormal3dv( next );
280         glVertex3d( radius * *(next + 0), radius * *(next + 1), radius * *(next + 2) );
281         glEnd();
282
283         tmp = row;
284         row = next;
285         next = tmp;
286     }
287
288     /* south pole */
289     glBegin( GL_TRIANGLE_FAN );
290     glNormal3d( 0.0, 0.0, -1.0 );
291     glVertex3d( 0.0, 0.0, -radius );
292     glNormal3dv( row );
293     glVertex3d( radius * *(row + 0), radius * *(row + 1), radius * *(row + 2) );
294
295     for( i=slices-1; i>=0; i-- )
296     {
297         glNormal3dv(row + 3 * i);
298         glVertex3d(
299             radius * *(row + 3 * i + 0),
300             radius * *(row + 3 * i + 1),
301                   radius * *(row + 3 * i + 2)
302            );
303     }
304
305     glEnd();
306
307     free(row);
308     free(next);
309     glPopMatrix();
310 }
311
312 /*
313  * Draws a wire cone
314  */
315 void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLint stacks )
316 {
317   double  alt   = height / (double) (stacks + 1);
318   double  angle = M_PI / (double) slices * 2.0;
319   double  slope = ( height / base );
320   double  sBase = base ;
321   double  sinNormal = ( base   / sqrt ( height * height + base * base )) ;
322   double  cosNormal = ( height / sqrt ( height * height + base * base )) ;
323
324   double *vertices = NULL;
325   int    i, j;
326
327   /*
328    * We need 'slices' points on a circle
329    */
330   vertices = (double *)calloc( sizeof(double), 2 * (slices + 1) );
331
332   for( j=0; j<slices+1; j++ )
333   {
334     vertices[ j*2 + 0 ] = cos( angle * j );
335     vertices[ j*2 + 1 ] = sin( angle * j );
336   }
337
338   /*
339    * First the cone's bottom...
340    */
341   for( j=0; j<slices; j++ )
342   {
343     glBegin( GL_LINE_LOOP );
344       glNormal3d( 0.0, 0.0, -1.0 );
345       glVertex3d( vertices[ (j+0)*2+0 ] * sBase, vertices[ (j+0)*2+1 ] * sBase, 0 );
346       glVertex3d( vertices[ (j+1)*2+0 ] * sBase, vertices[ (j+1)*2+1 ] * sBase, 0 );
347       glVertex3d( 0.0, 0.0, 0.0 );
348     glEnd();
349   }
350
351   /*
352    * Then all the stacks between the bottom and the top
353    */
354   for( i=0; i<stacks; i++ )
355   {
356     double alt_a = i * alt, alt_b = (i + 1) * alt;
357     double scl_a = (height - alt_a) / slope;
358     double scl_b = (height - alt_b) / slope;
359
360     for( j=0; j<slices; j++ )
361     {
362       glBegin( GL_LINE_LOOP );
363         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
364         glVertex3d( vertices[(j+0)*2+0] * scl_a, vertices[(j+0)*2+1] * scl_a, alt_a );
365         glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
366         glVertex3d( vertices[(j+1)*2+0] * scl_a, vertices[(j+1)*2+1] * scl_a, alt_a );
367         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
368         glVertex3d( vertices[(j+0)*2+0] * scl_b, vertices[(j+0)*2+1] * scl_b, alt_b );
369       glEnd();
370
371       glBegin( GL_LINE_LOOP );
372         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
373         glVertex3d( vertices[(j+0)*2+0] * scl_b, vertices[(j+0)*2+1] * scl_b, alt_b );
374         glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
375         glVertex3d( vertices[(j+1)*2+0] * scl_b, vertices[(j+1)*2+1] * scl_b, alt_b );
376         glVertex3d( vertices[(j+1)*2+0] * scl_a, vertices[(j+1)*2+1] * scl_a, alt_a );
377       glEnd();
378     }
379   }
380
381   /*
382    * Finally have the top part drawn...
383    */
384   for( j=0; j<slices; j++ )
385   {
386     double scl = alt / slope;
387
388     glBegin( GL_LINE_LOOP );
389       glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
390       glVertex3d( vertices[ (j+0)*2+0 ] * scl, vertices[ (j+0)*2+1 ] * scl, height - alt );
391       glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
392       glVertex3d( vertices[ (j+1)*2+0 ] * scl, vertices[ (j+1)*2+1 ] * scl, height - alt );
393       glVertex3d( 0, 0, height );
394     glEnd();
395   }
396 }
397
398 /*
399  * Draws a solid cone
400  */
401 void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLint stacks )
402 {
403   double  alt   = height / (double) (stacks + 1);
404   double  angle = M_PI / (double) slices * 2.0f;
405   double  slope = ( height / base );
406   double  sBase = base ;
407   double  sinNormal = ( base   / sqrt ( height * height + base * base )) ;
408   double  cosNormal = ( height / sqrt ( height * height + base * base )) ;
409
410   double *vertices = NULL;
411   int    i, j;
412
413   /*
414    * We need 'slices' points on a circle
415    */
416   vertices = (double *)calloc( sizeof(double), 2 * (slices + 1) );
417
418   for( j=0; j<slices+1; j++ )
419   {
420     vertices[ j*2 + 0 ] = cos( angle * j );
421     vertices[ j*2 + 1 ] = sin( angle * j );
422   }
423
424   /*
425    * First the cone's bottom...
426    */
427   for( j=0; j<slices; j++ )
428   {
429     glBegin( GL_TRIANGLES );
430       glNormal3d( 0.0, 0.0, -1.0 );
431       glVertex3d( vertices[ (j+0)*2+0 ] * sBase, vertices[ (j+0)*2+1 ] * sBase, 0 );
432       glVertex3d( vertices[ (j+1)*2+0 ] * sBase, vertices[ (j+1)*2+1 ] * sBase, 0 );
433       glVertex3d( 0.0, 0.0, 0.0 );
434     glEnd();
435   }
436
437   /*
438    * Then all the stacks between the bottom and the top
439    */
440   for( i=0; i<stacks; i++ )
441   {
442     double alt_a = i * alt, alt_b = (i + 1) * alt;
443     double scl_a = (height - alt_a) / slope;
444     double scl_b = (height - alt_b) / slope;
445
446     for( j=0; j<slices; j++ )
447     {
448       glBegin( GL_TRIANGLES );
449         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
450         glVertex3d( vertices[(j+0)*2+0] * scl_a, vertices[(j+0)*2+1] * scl_a, alt_a );
451         glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
452         glVertex3d( vertices[(j+1)*2+0] * scl_a, vertices[(j+1)*2+1] * scl_a, alt_a );
453         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
454         glVertex3d( vertices[(j+0)*2+0] * scl_b, vertices[(j+0)*2+1] * scl_b, alt_b );
455       glEnd();
456
457       glBegin( GL_TRIANGLES );
458         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
459         glVertex3d( vertices[(j+0)*2+0] * scl_b, vertices[(j+0)*2+1] * scl_b, alt_b );
460         glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
461         glVertex3d( vertices[(j+1)*2+0] * scl_b, vertices[(j+1)*2+1] * scl_b, alt_b );
462         glVertex3d( vertices[(j+1)*2+0] * scl_a, vertices[(j+1)*2+1] * scl_a, alt_a );
463       glEnd();
464     }
465   }
466
467   /*
468    * Finally have the top part drawn...
469    */
470   for( j=0; j<slices; j++ )
471   {
472     double scl = alt / slope;
473
474     glBegin( GL_TRIANGLES );
475       glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
476       glVertex3d( vertices[ (j+0)*2+0 ] * scl, vertices[ (j+0)*2+1 ] * scl, height - alt );
477       glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
478       glVertex3d( vertices[ (j+1)*2+0 ] * scl, vertices[ (j+1)*2+1 ] * scl, height - alt );
479       glVertex3d( 0, 0, height );
480     glEnd();
481   }
482 }
483
484 /*
485  *
486  */
487 void FGAPIENTRY glutWireTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings )
488 {
489   double  iradius = dInnerRadius, oradius = dOuterRadius, phi, psi, dpsi, dphi;
490   double *vertex, *normal;
491   int    i, j;
492   double spsi, cpsi, sphi, cphi ;
493
494   /*
495    * Allocate the vertices array
496    */
497   vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings );
498   normal = (double *)calloc( sizeof(double), 3 * nSides * nRings );
499
500   glPushMatrix();
501
502   dpsi = 2.0 * M_PI / (double)nRings ;
503   dphi = 2.0 * M_PI / (double)nSides ;
504   psi  = 0.0;
505
506   for( j=0; j<nRings; j++ )
507   {
508     cpsi = cos ( psi ) ;
509     spsi = sin ( psi ) ;
510     phi = 0.0;
511
512     for( i=0; i<nSides; i++ )
513     {
514       int offset = 3 * ( j * nSides + i ) ;
515       cphi = cos ( phi ) ;
516       sphi = sin ( phi ) ;
517       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
518       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
519       *(vertex + offset + 2) =                    sphi * iradius   ;
520       *(normal + offset + 0) = cpsi * cphi ;
521       *(normal + offset + 1) = spsi * cphi ;
522       *(normal + offset + 2) =        sphi ;
523       phi += dphi;
524     }
525
526     psi += dpsi;
527   }
528
529   for( i=0; i<nSides; i++ )
530   {
531     glBegin( GL_LINE_LOOP );
532
533     for( j=0; j<nRings; j++ )
534     {
535       int offset = 3 * ( j * nSides + i ) ;
536       glNormal3dv( normal + offset );
537       glVertex3dv( vertex + offset );
538     }
539
540     glEnd();
541   }
542
543   for( j=0; j<nRings; j++ )
544   {
545     glBegin(GL_LINE_LOOP);
546
547     for( i=0; i<nSides; i++ )
548     {
549       int offset = 3 * ( j * nSides + i ) ;
550       glNormal3dv( normal + offset );
551       glVertex3dv( vertex + offset );
552     }
553
554     glEnd();
555   }
556
557   free ( vertex ) ;
558   free ( normal ) ;
559   glPopMatrix();
560 }
561
562 /*
563  *
564  */
565 void FGAPIENTRY glutSolidTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings )
566 {
567   double  iradius = dInnerRadius, oradius = dOuterRadius, phi, psi, dpsi, dphi;
568   double *vertex, *normal;
569   int    i, j;
570   double spsi, cpsi, sphi, cphi ;
571
572   /*
573    * Increment the number of sides and rings to allow for one more point than surface
574    */
575   nSides ++ ;
576   nRings ++ ;
577
578   /*
579    * Allocate the vertices array
580    */
581   vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings );
582   normal = (double *)calloc( sizeof(double), 3 * nSides * nRings );
583
584   glPushMatrix();
585
586   dpsi = 2.0 * M_PI / (double)(nRings - 1) ;
587   dphi = 2.0 * M_PI / (double)(nSides - 1) ;
588   psi  = 0.0;
589
590   for( j=0; j<nRings; j++ )
591   {
592     cpsi = cos ( psi ) ;
593     spsi = sin ( psi ) ;
594     phi = 0.0;
595
596     for( i=0; i<nSides; i++ )
597     {
598       int offset = 3 * ( j * nSides + i ) ;
599       cphi = cos ( phi ) ;
600       sphi = sin ( phi ) ;
601       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
602       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
603       *(vertex + offset + 2) =                    sphi * iradius   ;
604       *(normal + offset + 0) = cpsi * cphi ;
605       *(normal + offset + 1) = spsi * cphi ;
606       *(normal + offset + 2) =        sphi ;
607       phi += dphi;
608     }
609
610     psi += dpsi;
611   }
612
613     glBegin( GL_QUADS );
614   for( i=0; i<nSides-1; i++ )
615   {
616     for( j=0; j<nRings-1; j++ )
617     {
618       int offset = 3 * ( j * nSides + i ) ;
619       glNormal3dv( normal + offset );
620       glVertex3dv( vertex + offset );
621       glNormal3dv( normal + offset + 3 );
622       glVertex3dv( vertex + offset + 3 );
623       glNormal3dv( normal + offset + 3 * nSides + 3 );
624       glVertex3dv( vertex + offset + 3 * nSides + 3 );
625       glNormal3dv( normal + offset + 3 * nSides );
626       glVertex3dv( vertex + offset + 3 * nSides );
627     }
628   }
629
630   glEnd();
631
632   free ( vertex ) ;
633   free ( normal ) ;
634   glPopMatrix();
635 }
636
637 /*
638  *
639  */
640 void FGAPIENTRY glutWireDodecahedron( void )
641 {
642   /* Magic Numbers:  It is possible to create a dodecahedron by attaching two pentagons to each face of
643    * of a cube.  The coordinates of the points are:
644    *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
645    * where x = 0.61803398875 and z = 1.61803398875.
646    */
647   glBegin ( GL_LINE_LOOP ) ;
648   glNormal3d (  0.0,  0.525731112119,  0.850650808354 ) ; glVertex3d (  0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( -0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
649   glEnd () ;
650   glBegin ( GL_LINE_LOOP ) ;
651   glNormal3d (  0.0,  0.525731112119, -0.850650808354 ) ; glVertex3d (  0.0,  1.61803398875, -0.61803398875 ) ; glVertex3d (  1.0,  1.0, -1.0 ) ; glVertex3d (  0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -1.0,  1.0, -1.0 ) ;
652   glEnd () ;
653   glBegin ( GL_LINE_LOOP ) ;
654   glNormal3d (  0.0, -0.525731112119,  0.850650808354 ) ; glVertex3d (  0.0, -1.61803398875,  0.61803398875 ) ; glVertex3d (  1.0, -1.0,  1.0 ) ; glVertex3d (  0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d ( -1.0, -1.0,  1.0 ) ;
655   glEnd () ;
656   glBegin ( GL_LINE_LOOP ) ;
657   glNormal3d (  0.0, -0.525731112119, -0.850650808354 ) ; glVertex3d (  0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d (  0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d (  1.0, -1.0, -1.0 ) ;
658   glEnd () ;
659
660   glBegin ( GL_LINE_LOOP ) ;
661   glNormal3d (  0.850650808354,  0.0,  0.525731112119 ) ; glVertex3d (  0.61803398875,  0.0,  1.61803398875 ) ; glVertex3d (  1.0, -1.0,  1.0 ) ; glVertex3d (  1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d (  1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
662   glEnd () ;
663   glBegin ( GL_LINE_LOOP ) ;
664   glNormal3d ( -0.850650808354,  0.0,  0.525731112119 ) ; glVertex3d ( -0.61803398875,  0.0,  1.61803398875 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( -1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.0, -1.0,  1.0 ) ;
665   glEnd () ;
666   glBegin ( GL_LINE_LOOP ) ;
667   glNormal3d (  0.850650808354,  0.0, -0.525731112119 ) ; glVertex3d (  0.61803398875,  0.0, -1.61803398875 ) ; glVertex3d (  1.0,  1.0, -1.0 ) ; glVertex3d (  1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d (  1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d (  1.0, -1.0, -1.0 ) ;
668   glEnd () ;
669   glBegin ( GL_LINE_LOOP ) ;
670   glNormal3d ( -0.850650808354,  0.0, -0.525731112119 ) ; glVertex3d ( -0.61803398875,  0.0, -1.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d ( -1.0,  1.0, -1.0 ) ;
671   glEnd () ;
672
673   glBegin ( GL_LINE_LOOP ) ;
674   glNormal3d (  0.525731112119,  0.850650808354,  0.0 ) ; glVertex3d (  1.61803398875,  0.61803398875,  0.0 ) ; glVertex3d (  1.0,  1.0, -1.0 ) ; glVertex3d ( 0.0,  1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
675   glEnd () ;
676   glBegin ( GL_LINE_LOOP ) ;
677   glNormal3d (  0.525731112119, -0.850650808354,  0.0 ) ; glVertex3d (  1.61803398875, -0.61803398875,  0.0 ) ; glVertex3d (  1.0, -1.0,  1.0 ) ; glVertex3d ( 0.0, -1.61803398875,  0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d (  1.0, -1.0, -1.0 ) ;
678   glEnd () ;
679   glBegin ( GL_LINE_LOOP ) ;
680   glNormal3d ( -0.525731112119,  0.850650808354,  0.0 ) ; glVertex3d ( -1.61803398875,  0.61803398875,  0.0 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( 0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d ( 0.0,  1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0,  1.0, -1.0 ) ;
681   glEnd () ;
682   glBegin ( GL_LINE_LOOP ) ;
683   glNormal3d ( -0.525731112119, -0.850650808354,  0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875,  0.0 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875,  0.61803398875 ) ; glVertex3d ( -1.0, -1.0,  1.0 ) ;
684   glEnd () ;
685 }
686
687 /*
688  *
689  */
690 void FGAPIENTRY glutSolidDodecahedron( void )
691 {
692   /* Magic Numbers:  It is possible to create a dodecahedron by attaching two pentagons to each face of
693    * of a cube.  The coordinates of the points are:
694    *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
695    * where x = 0.61803398875 and z = 1.61803398875.
696    */
697   glBegin ( GL_POLYGON ) ;
698   glNormal3d (  0.0,  0.525731112119,  0.850650808354 ) ; glVertex3d (  0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( -0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
699   glEnd () ;
700   glBegin ( GL_POLYGON ) ;
701   glNormal3d (  0.0,  0.525731112119, -0.850650808354 ) ; glVertex3d (  0.0,  1.61803398875, -0.61803398875 ) ; glVertex3d (  1.0,  1.0, -1.0 ) ; glVertex3d (  0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -1.0,  1.0, -1.0 ) ;
702   glEnd () ;
703   glBegin ( GL_POLYGON ) ;
704   glNormal3d (  0.0, -0.525731112119,  0.850650808354 ) ; glVertex3d (  0.0, -1.61803398875,  0.61803398875 ) ; glVertex3d (  1.0, -1.0,  1.0 ) ; glVertex3d (  0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d ( -1.0, -1.0,  1.0 ) ;
705   glEnd () ;
706   glBegin ( GL_POLYGON ) ;
707   glNormal3d (  0.0, -0.525731112119, -0.850650808354 ) ; glVertex3d (  0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d (  0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d (  1.0, -1.0, -1.0 ) ;
708   glEnd () ;
709
710   glBegin ( GL_POLYGON ) ;
711   glNormal3d (  0.850650808354,  0.0,  0.525731112119 ) ; glVertex3d (  0.61803398875,  0.0,  1.61803398875 ) ; glVertex3d (  1.0, -1.0,  1.0 ) ; glVertex3d (  1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d (  1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
712   glEnd () ;
713   glBegin ( GL_POLYGON ) ;
714   glNormal3d ( -0.850650808354,  0.0,  0.525731112119 ) ; glVertex3d ( -0.61803398875,  0.0,  1.61803398875 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( -1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.0, -1.0,  1.0 ) ;
715   glEnd () ;
716   glBegin ( GL_POLYGON ) ;
717   glNormal3d (  0.850650808354,  0.0, -0.525731112119 ) ; glVertex3d (  0.61803398875,  0.0, -1.61803398875 ) ; glVertex3d (  1.0,  1.0, -1.0 ) ; glVertex3d (  1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d (  1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d (  1.0, -1.0, -1.0 ) ;
718   glEnd () ;
719   glBegin ( GL_POLYGON ) ;
720   glNormal3d ( -0.850650808354,  0.0, -0.525731112119 ) ; glVertex3d ( -0.61803398875,  0.0, -1.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875,  0.61803398875, 0.0 ) ; glVertex3d ( -1.0,  1.0, -1.0 ) ;
721   glEnd () ;
722
723   glBegin ( GL_POLYGON ) ;
724   glNormal3d (  0.525731112119,  0.850650808354,  0.0 ) ; glVertex3d (  1.61803398875,  0.61803398875,  0.0 ) ; glVertex3d (  1.0,  1.0, -1.0 ) ; glVertex3d ( 0.0,  1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
725   glEnd () ;
726   glBegin ( GL_POLYGON ) ;
727   glNormal3d (  0.525731112119, -0.850650808354,  0.0 ) ; glVertex3d (  1.61803398875, -0.61803398875,  0.0 ) ; glVertex3d (  1.0, -1.0,  1.0 ) ; glVertex3d ( 0.0, -1.61803398875,  0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d (  1.0, -1.0, -1.0 ) ;
728   glEnd () ;
729   glBegin ( GL_POLYGON ) ;
730   glNormal3d ( -0.525731112119,  0.850650808354,  0.0 ) ; glVertex3d ( -1.61803398875,  0.61803398875,  0.0 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( 0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d ( 0.0,  1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0,  1.0, -1.0 ) ;
731   glEnd () ;
732   glBegin ( GL_POLYGON ) ;
733   glNormal3d ( -0.525731112119, -0.850650808354,  0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875,  0.0 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875,  0.61803398875 ) ; glVertex3d ( -1.0, -1.0,  1.0 ) ;
734   glEnd () ;
735 }
736
737 /*
738  *
739  */
740 void FGAPIENTRY glutWireOctahedron( void )
741 {
742 #define RADIUS    1.0f
743   glBegin( GL_LINE_LOOP );
744     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
745     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
746     glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
747     glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
748     glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
749     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
750     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
751     glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
752   glEnd();
753 #undef RADIUS
754 }
755
756 /*
757  *
758  */
759 void FGAPIENTRY glutSolidOctahedron( void )
760 {
761 #define RADIUS    1.0f
762   glBegin( GL_TRIANGLES );
763     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
764     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
765     glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
766     glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
767     glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
768     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
769     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
770     glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
771   glEnd();
772 #undef RADIUS
773 }
774
775 /*
776  *
777  */
778 void FGAPIENTRY glutWireTetrahedron( void )
779 {
780   /* Magic Numbers:  r0 = ( 1, 0, 0 )
781    *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
782    *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
783    *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
784    * |r0| = |r1| = |r2| = |r3| = 1
785    * Distance between any two points is 2 sqrt(6) / 3
786    *
787    * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
788    */
789
790   double r0[3] = {             1.0,             0.0,             0.0 } ;
791   double r1[3] = { -0.333333333333,  0.942809041582,             0.0 } ;
792   double r2[3] = { -0.333333333333, -0.471404520791,  0.816496580928 } ;
793   double r3[3] = { -0.333333333333, -0.471404520791, -0.816496580928 } ;
794
795   glBegin( GL_LINE_LOOP ) ;
796     glNormal3d (           -1.0,             0.0,             0.0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r2 ) ;
797     glNormal3d ( 0.333333333333, -0.942809041582,             0.0 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r2 ) ; glVertex3dv ( r3 ) ;
798     glNormal3d ( 0.333333333333,  0.471404520791, -0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r1 ) ;
799     glNormal3d ( 0.333333333333,  0.471404520791,  0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r2 ) ;
800   glEnd() ;
801 }
802
803 /*
804  *
805  */
806 void FGAPIENTRY glutSolidTetrahedron( void )
807 {
808   /* Magic Numbers:  r0 = ( 1, 0, 0 )
809    *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
810    *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
811    *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
812    * |r0| = |r1| = |r2| = |r3| = 1
813    * Distance between any two points is 2 sqrt(6) / 3
814    *
815    * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
816    */
817
818   double r0[3] = {             1.0,             0.0,             0.0 } ;
819   double r1[3] = { -0.333333333333,  0.942809041582,             0.0 } ;
820   double r2[3] = { -0.333333333333, -0.471404520791,  0.816496580928 } ;
821   double r3[3] = { -0.333333333333, -0.471404520791, -0.816496580928 } ;
822
823   glBegin( GL_TRIANGLES ) ;
824     glNormal3d (           -1.0,             0.0,             0.0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r2 ) ;
825     glNormal3d ( 0.333333333333, -0.942809041582,             0.0 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r2 ) ; glVertex3dv ( r3 ) ;
826     glNormal3d ( 0.333333333333,  0.471404520791, -0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r1 ) ;
827     glNormal3d ( 0.333333333333,  0.471404520791,  0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r2 ) ;
828   glEnd() ;
829 }
830
831 /*
832  *
833  */
834 double icos_r[12][3] = { { 1.0, 0.0, 0.0 },
835   {  0.447213595500,  0.894427191000, 0.0 }, {  0.447213595500,  0.276393202252, 0.850650808354 }, {  0.447213595500, -0.723606797748, 0.525731112119 }, {  0.447213595500, -0.723606797748, -0.525731112119 }, {  0.447213595500,  0.276393202252, -0.850650808354 },
836   { -0.447213595500, -0.894427191000, 0.0 }, { -0.447213595500, -0.276393202252, 0.850650808354 }, { -0.447213595500,  0.723606797748, 0.525731112119 }, { -0.447213595500,  0.723606797748, -0.525731112119 }, { -0.447213595500, -0.276393202252, -0.850650808354 },
837   { -1.0, 0.0, 0.0 } } ;
838 int icos_v [20][3] = { { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 4 }, { 0, 4, 5 }, { 0, 5, 1 },
839                        { 1, 8, 2 }, { 2, 7, 3 }, { 3, 6, 4 }, { 4, 10, 5 }, { 5, 9, 1 },
840                        { 1, 9, 8 }, { 2, 8, 7 }, { 3, 7, 6 }, { 4, 6, 10 }, { 5, 10, 9 },
841                        { 11, 9, 10 }, { 11, 8, 9 }, { 11, 7, 8 }, { 11, 6, 7 }, { 11, 10, 6 } } ;
842
843 void FGAPIENTRY glutWireIcosahedron( void )
844 {
845   int i ;
846   for ( i = 0; i < 20; i++ )
847   {
848     double normal[3] ;
849     normal[0] = ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) - ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) ;
850     normal[1] = ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) - ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) ;
851     normal[2] = ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) - ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) ;
852     glBegin ( GL_LINE_LOOP ) ;
853       glNormal3dv ( normal ) ;
854       glVertex3dv ( icos_r[icos_v[i][0]] ) ;
855       glVertex3dv ( icos_r[icos_v[i][1]] ) ;
856       glVertex3dv ( icos_r[icos_v[i][2]] ) ;
857     glEnd () ;
858   }
859 }
860
861 /*
862  *
863  */
864 void FGAPIENTRY glutSolidIcosahedron( void )
865 {
866   int i ;
867
868   glBegin ( GL_TRIANGLES ) ;
869   for ( i = 0; i < 20; i++ )
870   {
871     double normal[3] ;
872     normal[0] = ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) - ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) ;
873     normal[1] = ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) - ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) ;
874     normal[2] = ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) - ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) ;
875       glNormal3dv ( normal ) ;
876       glVertex3dv ( icos_r[icos_v[i][0]] ) ;
877       glVertex3dv ( icos_r[icos_v[i][1]] ) ;
878       glVertex3dv ( icos_r[icos_v[i][2]] ) ;
879   }
880
881   glEnd () ;
882 }
883
884 /*
885  *
886  */
887 double rdod_r[14][3] = { { 0.0, 0.0, 1.0 },
888   {  0.707106781187,  0.000000000000,  0.5 }, {  0.000000000000,  0.707106781187,  0.5 }, { -0.707106781187,  0.000000000000,  0.5 }, {  0.000000000000, -0.707106781187,  0.5 },
889   {  0.707106781187,  0.707106781187,  0.0 }, { -0.707106781187,  0.707106781187,  0.0 }, { -0.707106781187, -0.707106781187,  0.0 }, {  0.707106781187, -0.707106781187,  0.0 },
890   {  0.707106781187,  0.000000000000, -0.5 }, {  0.000000000000,  0.707106781187, -0.5 }, { -0.707106781187,  0.000000000000, -0.5 }, {  0.000000000000, -0.707106781187, -0.5 },
891   {  0.0, 0.0, -1.0 } } ;
892 int rdod_v [12][4] = { { 0,  1,  5,  2 }, { 0,  2,  6,  3 }, { 0,  3,  7,  4 }, { 0,  4,  8, 1 },
893                        { 5, 10,  6,  2 }, { 6, 11,  7,  3 }, { 7, 12,  8,  4 }, { 8,  9,  5, 1 },
894                        { 5,  9, 13, 10 }, { 6, 10, 13, 11 }, { 7, 11, 13, 12 }, { 8, 12, 13, 9 } } ;
895 double rdod_n[12][3] = {
896   {  0.353553390594,  0.353553390594,  0.5 }, { -0.353553390594,  0.353553390594,  0.5 }, { -0.353553390594, -0.353553390594,  0.5 }, {  0.353553390594, -0.353553390594,  0.5 },
897   {  0.000000000000,  1.000000000000,  0.0 }, { -1.000000000000,  0.000000000000,  0.0 }, {  0.000000000000, -1.000000000000,  0.0 }, {  1.000000000000,  0.000000000000,  0.0 },
898   {  0.353553390594,  0.353553390594, -0.5 }, { -0.353553390594,  0.353553390594, -0.5 }, { -0.353553390594, -0.353553390594, -0.5 }, {  0.353553390594, -0.353553390594, -0.5 }
899   } ;
900
901 void FGAPIENTRY glutWireRhombicDodecahedron( void )
902 {
903   int i ;
904   for ( i = 0; i < 12; i++ )
905   {
906     glBegin ( GL_LINE_LOOP ) ;
907       glNormal3dv ( rdod_n[i] ) ;
908       glVertex3dv ( rdod_r[rdod_v[i][0]] ) ;
909       glVertex3dv ( rdod_r[rdod_v[i][1]] ) ;
910       glVertex3dv ( rdod_r[rdod_v[i][2]] ) ;
911       glVertex3dv ( rdod_r[rdod_v[i][3]] ) ;
912     glEnd () ;
913   }
914 }
915
916 /*
917  *
918  */
919 void FGAPIENTRY glutSolidRhombicDodecahedron( void )
920 {
921   int i ;
922
923   glBegin ( GL_QUADS ) ;
924   for ( i = 0; i < 12; i++ )
925   {
926       glNormal3dv ( rdod_n[i] ) ;
927       glVertex3dv ( rdod_r[rdod_v[i][0]] ) ;
928       glVertex3dv ( rdod_r[rdod_v[i][1]] ) ;
929       glVertex3dv ( rdod_r[rdod_v[i][2]] ) ;
930       glVertex3dv ( rdod_r[rdod_v[i][3]] ) ;
931   }
932
933   glEnd () ;
934 }
935
936 #define NUM_FACES     4
937
938 static GLdouble tetrahedron_v[4][3] =  /* Vertices */
939 {
940   { -0.5, -0.288675134595, -0.144337567297 },
941   {  0.5, -0.288675134595, -0.144337567297 },
942   {  0.0,  0.577350269189, -0.144337567297 },
943   {  0.0,  0.0,             0.672159013631 }
944 } ;
945
946 static GLint tetrahedron_i[4][3] =  /* Vertex indices */
947 {
948   { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 1 }, { 1, 3, 2 }
949 } ;
950
951 static GLdouble tetrahedron_n[4][3] =  /* Normals */
952 {
953   {  0.0,             0.0,            -1.0 },
954   { -0.816496580928,  0.471404520791,  0.333333333333 },
955   {  0.0,            -0.942809041582,  0.333333333333 },
956   {  0.816496580928,  0.471404520791,  0.333333333333 }
957 } ;
958
959 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale )
960 {
961   int i, j ;
962
963   if ( num_levels == 0 )
964   {
965
966     for ( i = 0 ; i < NUM_FACES ; i++ )
967     {
968       glBegin ( GL_LINE_LOOP ) ;
969       glNormal3dv ( tetrahedron_n[i] ) ;
970       for ( j = 0; j < 3; j++ )
971       {
972         double x = offset[0] + scale * tetrahedron_v[tetrahedron_i[i][j]][0] ;
973         double y = offset[1] + scale * tetrahedron_v[tetrahedron_i[i][j]][1] ;
974         double z = offset[2] + scale * tetrahedron_v[tetrahedron_i[i][j]][2] ;
975         glVertex3d ( x, y, z ) ;
976       }
977
978       glEnd () ;
979     }
980   }
981   else
982   {
983     GLdouble local_offset[3] ;  /* Use a local variable to avoid buildup of roundoff errors */
984     num_levels -- ;
985     scale /= 2.0 ;
986     local_offset[0] = offset[0] + scale * tetrahedron_v[0][0] ;
987     local_offset[1] = offset[1] + scale * tetrahedron_v[0][1] ;
988     local_offset[2] = offset[2] + scale * tetrahedron_v[0][2] ;
989     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
990     local_offset[0] += scale ;
991     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
992     local_offset[0] -= 0.5            * scale ;
993     local_offset[1] += 0.866025403784 * scale ;
994     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
995     local_offset[1] -= 0.577350269189 * scale ;
996     local_offset[2] += 0.816496580928 * scale ;
997     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
998   }
999 }
1000
1001 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale )
1002 {
1003   int i, j ;
1004
1005   if ( num_levels == 0 )
1006   {
1007     glBegin ( GL_TRIANGLES ) ;
1008
1009     for ( i = 0 ; i < NUM_FACES ; i++ )
1010     {
1011       glNormal3dv ( tetrahedron_n[i] ) ;
1012       for ( j = 0; j < 3; j++ )
1013       {
1014         double x = offset[0] + scale * tetrahedron_v[tetrahedron_i[i][j]][0] ;
1015         double y = offset[1] + scale * tetrahedron_v[tetrahedron_i[i][j]][1] ;
1016         double z = offset[2] + scale * tetrahedron_v[tetrahedron_i[i][j]][2] ;
1017         glVertex3d ( x, y, z ) ;
1018       }
1019     }
1020
1021     glEnd () ;
1022   }
1023   else
1024   {
1025     GLdouble local_offset[3] ;  /* Use a local variable to avoid buildup of roundoff errors */
1026     num_levels -- ;
1027     scale /= 2.0 ;
1028     local_offset[0] = offset[0] + scale * tetrahedron_v[0][0] ;
1029     local_offset[1] = offset[1] + scale * tetrahedron_v[0][1] ;
1030     local_offset[2] = offset[2] + scale * tetrahedron_v[0][2] ;
1031     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1032     local_offset[0] += scale ;
1033     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1034     local_offset[0] -= 0.5            * scale ;
1035     local_offset[1] += 0.866025403784 * scale ;
1036     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1037     local_offset[1] -= 0.577350269189 * scale ;
1038     local_offset[2] += 0.816496580928 * scale ;
1039     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1040   }
1041 }
1042
1043 #undef NUM_FACES
1044
1045 /*** END OF FILE ***/