Got rid of the G_LOG_DOMAIN junk, per discussion on the mailing list.
[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     double scl = height / slope;
430
431     glBegin( GL_TRIANGLES );
432       glNormal3d( 0.0, 0.0, -1.0 );
433       glVertex3d( vertices[ (j+0)*2+0 ] * sBase, vertices[ (j+0)*2+1 ] * sBase, 0 );
434       glVertex3d( vertices[ (j+1)*2+0 ] * sBase, vertices[ (j+1)*2+1 ] * sBase, 0 );
435       glVertex3d( 0.0, 0.0, 0.0 );
436     glEnd();
437   }
438
439   /*
440    * Then all the stacks between the bottom and the top
441    */
442   for( i=0; i<stacks; i++ )
443   {
444     double alt_a = i * alt, alt_b = (i + 1) * alt;
445     double scl_a = (height - alt_a) / slope;
446     double scl_b = (height - alt_b) / slope;
447
448     for( j=0; j<slices; j++ )
449     {
450       glBegin( GL_TRIANGLES );
451         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
452         glVertex3d( vertices[(j+0)*2+0] * scl_a, vertices[(j+0)*2+1] * scl_a, alt_a );
453         glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
454         glVertex3d( vertices[(j+1)*2+0] * scl_a, vertices[(j+1)*2+1] * scl_a, alt_a );
455         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
456         glVertex3d( vertices[(j+0)*2+0] * scl_b, vertices[(j+0)*2+1] * scl_b, alt_b );
457       glEnd();
458
459       glBegin( GL_TRIANGLES );
460         glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
461         glVertex3d( vertices[(j+0)*2+0] * scl_b, vertices[(j+0)*2+1] * scl_b, alt_b );
462         glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
463         glVertex3d( vertices[(j+1)*2+0] * scl_b, vertices[(j+1)*2+1] * scl_b, alt_b );
464         glVertex3d( vertices[(j+1)*2+0] * scl_a, vertices[(j+1)*2+1] * scl_a, alt_a );
465       glEnd();
466     }
467   }
468
469   /*
470    * Finally have the top part drawn...
471    */
472   for( j=0; j<slices; j++ )
473   {
474     double scl = alt / slope;
475
476     glBegin( GL_TRIANGLES );
477       glNormal3d( sinNormal * vertices[(j+0)*2+0], sinNormal * vertices[(j+0)*2+1], cosNormal ) ;
478       glVertex3d( vertices[ (j+0)*2+0 ] * scl, vertices[ (j+0)*2+1 ] * scl, height - alt );
479       glNormal3d( sinNormal * vertices[(j+1)*2+0], sinNormal * vertices[(j+1)*2+1], cosNormal ) ;
480       glVertex3d( vertices[ (j+1)*2+0 ] * scl, vertices[ (j+1)*2+1 ] * scl, height - alt );
481       glVertex3d( 0, 0, height );
482     glEnd();
483   }
484 }
485
486 /*
487  *
488  */
489 void FGAPIENTRY glutWireTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings )
490 {
491   double  iradius = dInnerRadius, oradius = dOuterRadius, phi, psi, dpsi, dphi;
492   double *vertex, *normal;
493   int    i, j;
494   double spsi, cpsi, sphi, cphi ;
495
496   /*
497    * Allocate the vertices array
498    */
499   vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings );
500   normal = (double *)calloc( sizeof(double), 3 * nSides * nRings );
501
502   glPushMatrix();
503
504   dpsi = 2.0 * M_PI / (double)nRings ;
505   dphi = 2.0 * M_PI / (double)nSides ;
506   psi  = 0.0;
507
508   for( j=0; j<nRings; j++ )
509   {
510     cpsi = cos ( psi ) ;
511     spsi = sin ( psi ) ;
512     phi = 0.0;
513
514     for( i=0; i<nSides; i++ )
515     {
516       int offset = 3 * ( j * nSides + i ) ;
517       cphi = cos ( phi ) ;
518       sphi = sin ( phi ) ;
519       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
520       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
521       *(vertex + offset + 2) =                    sphi * iradius   ;
522       *(normal + offset + 0) = cpsi * cphi ;
523       *(normal + offset + 1) = spsi * cphi ;
524       *(normal + offset + 2) =        sphi ;
525       phi += dphi;
526     }
527
528     psi += dpsi;
529   }
530
531   for( i=0; i<nSides; i++ )
532   {
533     glBegin( GL_LINE_LOOP );
534
535     for( j=0; j<nRings; j++ )
536     {
537       int offset = 3 * ( j * nSides + i ) ;
538       glNormal3dv( normal + offset );
539       glVertex3dv( vertex + offset );
540     }
541
542     glEnd();
543   }
544
545   for( j=0; j<nRings; j++ )
546   {
547     glBegin(GL_LINE_LOOP);
548
549     for( i=0; i<nSides; i++ )
550     {
551       int offset = 3 * ( j * nSides + i ) ;
552       glNormal3dv( normal + offset );
553       glVertex3dv( vertex + offset );
554     }
555
556     glEnd();
557   }
558
559   free ( vertex ) ;
560   free ( normal ) ;
561   glPopMatrix();
562 }
563
564 /*
565  *
566  */
567 void FGAPIENTRY glutSolidTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings )
568 {
569   double  iradius = dInnerRadius, oradius = dOuterRadius, phi, psi, dpsi, dphi;
570   double *vertex, *normal;
571   int    i, j;
572   double spsi, cpsi, sphi, cphi ;
573
574   /*
575    * Increment the number of sides and rings to allow for one more point than surface
576    */
577   nSides ++ ;
578   nRings ++ ;
579
580   /*
581    * Allocate the vertices array
582    */
583   vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings );
584   normal = (double *)calloc( sizeof(double), 3 * nSides * nRings );
585
586   glPushMatrix();
587
588   dpsi = 2.0 * M_PI / (double)(nRings - 1) ;
589   dphi = 2.0 * M_PI / (double)(nSides - 1) ;
590   psi  = 0.0;
591
592   for( j=0; j<nRings; j++ )
593   {
594     cpsi = cos ( psi ) ;
595     spsi = sin ( psi ) ;
596     phi = 0.0;
597
598     for( i=0; i<nSides; i++ )
599     {
600       int offset = 3 * ( j * nSides + i ) ;
601       cphi = cos ( phi ) ;
602       sphi = sin ( phi ) ;
603       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
604       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
605       *(vertex + offset + 2) =                    sphi * iradius   ;
606       *(normal + offset + 0) = cpsi * cphi ;
607       *(normal + offset + 1) = spsi * cphi ;
608       *(normal + offset + 2) =        sphi ;
609       phi += dphi;
610     }
611
612     psi += dpsi;
613   }
614
615     glBegin( GL_QUADS );
616   for( i=0; i<nSides-1; i++ )
617   {
618     for( j=0; j<nRings-1; j++ )
619     {
620       int offset = 3 * ( j * nSides + i ) ;
621       glNormal3dv( normal + offset );
622       glVertex3dv( vertex + offset );
623       glNormal3dv( normal + offset + 3 );
624       glVertex3dv( vertex + offset + 3 );
625       glNormal3dv( normal + offset + 3 * nSides + 3 );
626       glVertex3dv( vertex + offset + 3 * nSides + 3 );
627       glNormal3dv( normal + offset + 3 * nSides );
628       glVertex3dv( vertex + offset + 3 * nSides );
629     }
630   }
631
632   glEnd();
633
634   free ( vertex ) ;
635   free ( normal ) ;
636   glPopMatrix();
637 }
638
639 /*
640  *
641  */
642 void FGAPIENTRY glutWireDodecahedron( void )
643 {
644   /* Magic Numbers:  It is possible to create a dodecahedron by attaching two pentagons to each face of
645    * of a cube.  The coordinates of the points are:
646    *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
647    * where x = 0.61803398875 and z = 1.61803398875.
648    */
649   glBegin ( GL_LINE_LOOP ) ;
650   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 ) ;
651   glEnd () ;
652   glBegin ( GL_LINE_LOOP ) ;
653   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 ) ;
654   glEnd () ;
655   glBegin ( GL_LINE_LOOP ) ;
656   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 ) ;
657   glEnd () ;
658   glBegin ( GL_LINE_LOOP ) ;
659   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 ) ;
660   glEnd () ;
661
662   glBegin ( GL_LINE_LOOP ) ;
663   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 ) ;
664   glEnd () ;
665   glBegin ( GL_LINE_LOOP ) ;
666   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 ) ;
667   glEnd () ;
668   glBegin ( GL_LINE_LOOP ) ;
669   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 ) ;
670   glEnd () ;
671   glBegin ( GL_LINE_LOOP ) ;
672   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 ) ;
673   glEnd () ;
674
675   glBegin ( GL_LINE_LOOP ) ;
676   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 ) ;
677   glEnd () ;
678   glBegin ( GL_LINE_LOOP ) ;
679   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 ) ;
680   glEnd () ;
681   glBegin ( GL_LINE_LOOP ) ;
682   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 ) ;
683   glEnd () ;
684   glBegin ( GL_LINE_LOOP ) ;
685   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 ) ;
686   glEnd () ;
687 }
688
689 /*
690  *
691  */
692 void FGAPIENTRY glutSolidDodecahedron( void )
693 {
694   /* Magic Numbers:  It is possible to create a dodecahedron by attaching two pentagons to each face of
695    * of a cube.  The coordinates of the points are:
696    *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
697    * where x = 0.61803398875 and z = 1.61803398875.
698    */
699   glBegin ( GL_POLYGON ) ;
700   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 ) ;
701   glEnd () ;
702   glBegin ( GL_POLYGON ) ;
703   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 ) ;
704   glEnd () ;
705   glBegin ( GL_POLYGON ) ;
706   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 ) ;
707   glEnd () ;
708   glBegin ( GL_POLYGON ) ;
709   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 ) ;
710   glEnd () ;
711
712   glBegin ( GL_POLYGON ) ;
713   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 ) ;
714   glEnd () ;
715   glBegin ( GL_POLYGON ) ;
716   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 ) ;
717   glEnd () ;
718   glBegin ( GL_POLYGON ) ;
719   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 ) ;
720   glEnd () ;
721   glBegin ( GL_POLYGON ) ;
722   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 ) ;
723   glEnd () ;
724
725   glBegin ( GL_POLYGON ) ;
726   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 ) ;
727   glEnd () ;
728   glBegin ( GL_POLYGON ) ;
729   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 ) ;
730   glEnd () ;
731   glBegin ( GL_POLYGON ) ;
732   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 ) ;
733   glEnd () ;
734   glBegin ( GL_POLYGON ) ;
735   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 ) ;
736   glEnd () ;
737 }
738
739 /*
740  *
741  */
742 void FGAPIENTRY glutWireOctahedron( void )
743 {
744 #define RADIUS    1.0f
745   glBegin( GL_LINE_LOOP );
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     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 );
753     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 );
754   glEnd();
755 #undef RADIUS
756 }
757
758 /*
759  *
760  */
761 void FGAPIENTRY glutSolidOctahedron( void )
762 {
763 #define RADIUS    1.0f
764   glBegin( GL_TRIANGLES );
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     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 );
772     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 );
773   glEnd();
774 #undef RADIUS
775 }
776
777 /*
778  *
779  */
780 void FGAPIENTRY glutWireTetrahedron( void )
781 {
782   /* Magic Numbers:  r0 = ( 1, 0, 0 )
783    *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
784    *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
785    *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
786    * |r0| = |r1| = |r2| = |r3| = 1
787    * Distance between any two points is 2 sqrt(6) / 3
788    *
789    * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
790    */
791
792   double r0[3] = {             1.0,             0.0,             0.0 } ;
793   double r1[3] = { -0.333333333333,  0.942809041582,             0.0 } ;
794   double r2[3] = { -0.333333333333, -0.471404520791,  0.816496580928 } ;
795   double r3[3] = { -0.333333333333, -0.471404520791, -0.816496580928 } ;
796
797   glBegin( GL_LINE_LOOP ) ;
798     glNormal3d (           -1.0,             0.0,             0.0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r2 ) ;
799     glNormal3d ( 0.333333333333, -0.942809041582,             0.0 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r2 ) ; glVertex3dv ( r3 ) ;
800     glNormal3d ( 0.333333333333,  0.471404520791, -0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r1 ) ;
801     glNormal3d ( 0.333333333333,  0.471404520791,  0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r2 ) ;
802   glEnd() ;
803 }
804
805 /*
806  *
807  */
808 void FGAPIENTRY glutSolidTetrahedron( void )
809 {
810   /* Magic Numbers:  r0 = ( 1, 0, 0 )
811    *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
812    *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
813    *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
814    * |r0| = |r1| = |r2| = |r3| = 1
815    * Distance between any two points is 2 sqrt(6) / 3
816    *
817    * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
818    */
819
820   double r0[3] = {             1.0,             0.0,             0.0 } ;
821   double r1[3] = { -0.333333333333,  0.942809041582,             0.0 } ;
822   double r2[3] = { -0.333333333333, -0.471404520791,  0.816496580928 } ;
823   double r3[3] = { -0.333333333333, -0.471404520791, -0.816496580928 } ;
824
825   glBegin( GL_TRIANGLES ) ;
826     glNormal3d (           -1.0,             0.0,             0.0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r2 ) ;
827     glNormal3d ( 0.333333333333, -0.942809041582,             0.0 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r2 ) ; glVertex3dv ( r3 ) ;
828     glNormal3d ( 0.333333333333,  0.471404520791, -0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r1 ) ;
829     glNormal3d ( 0.333333333333,  0.471404520791,  0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r2 ) ;
830   glEnd() ;
831 }
832
833 /*
834  *
835  */
836 double icos_r[12][3] = { { 1.0, 0.0, 0.0 },
837   {  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 },
838   { -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 },
839   { -1.0, 0.0, 0.0 } } ;
840 int icos_v [20][3] = { { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 4 }, { 0, 4, 5 }, { 0, 5, 1 },
841                        { 1, 8, 2 }, { 2, 7, 3 }, { 3, 6, 4 }, { 4, 10, 5 }, { 5, 9, 1 },
842                        { 1, 9, 8 }, { 2, 8, 7 }, { 3, 7, 6 }, { 4, 6, 10 }, { 5, 10, 9 },
843                        { 11, 9, 10 }, { 11, 8, 9 }, { 11, 7, 8 }, { 11, 6, 7 }, { 11, 10, 6 } } ;
844
845 void FGAPIENTRY glutWireIcosahedron( void )
846 {
847   int i ;
848   for ( i = 0; i < 20; i++ )
849   {
850     double normal[3] ;
851     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] ) ;
852     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] ) ;
853     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] ) ;
854     glBegin ( GL_LINE_LOOP ) ;
855       glNormal3dv ( normal ) ;
856       glVertex3dv ( icos_r[icos_v[i][0]] ) ;
857       glVertex3dv ( icos_r[icos_v[i][1]] ) ;
858       glVertex3dv ( icos_r[icos_v[i][2]] ) ;
859     glEnd () ;
860   }
861 }
862
863 /*
864  *
865  */
866 void FGAPIENTRY glutSolidIcosahedron( void )
867 {
868   int i ;
869
870   glBegin ( GL_TRIANGLES ) ;
871   for ( i = 0; i < 20; i++ )
872   {
873     double normal[3] ;
874     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] ) ;
875     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] ) ;
876     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] ) ;
877       glNormal3dv ( normal ) ;
878       glVertex3dv ( icos_r[icos_v[i][0]] ) ;
879       glVertex3dv ( icos_r[icos_v[i][1]] ) ;
880       glVertex3dv ( icos_r[icos_v[i][2]] ) ;
881   }
882
883   glEnd () ;
884 }
885
886 /*
887  *
888  */
889 double rdod_r[14][3] = { { 0.0, 0.0, 1.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.707106781187,  0.707106781187,  0.0 }, { -0.707106781187,  0.707106781187,  0.0 }, { -0.707106781187, -0.707106781187,  0.0 }, {  0.707106781187, -0.707106781187,  0.0 },
892   {  0.707106781187,  0.000000000000, -0.5 }, {  0.000000000000,  0.707106781187, -0.5 }, { -0.707106781187,  0.000000000000, -0.5 }, {  0.000000000000, -0.707106781187, -0.5 },
893   {  0.0, 0.0, -1.0 } } ;
894 int rdod_v [12][4] = { { 0,  1,  5,  2 }, { 0,  2,  6,  3 }, { 0,  3,  7,  4 }, { 0,  4,  8, 1 },
895                        { 5, 10,  6,  2 }, { 6, 11,  7,  3 }, { 7, 12,  8,  4 }, { 8,  9,  5, 1 },
896                        { 5,  9, 13, 10 }, { 6, 10, 13, 11 }, { 7, 11, 13, 12 }, { 8, 12, 13, 9 } } ;
897 double rdod_n[12][3] = {
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   {  0.000000000000,  1.000000000000,  0.0 }, { -1.000000000000,  0.000000000000,  0.0 }, {  0.000000000000, -1.000000000000,  0.0 }, {  1.000000000000,  0.000000000000,  0.0 },
900   {  0.353553390594,  0.353553390594, -0.5 }, { -0.353553390594,  0.353553390594, -0.5 }, { -0.353553390594, -0.353553390594, -0.5 }, {  0.353553390594, -0.353553390594, -0.5 }
901   } ;
902
903 void FGAPIENTRY glutWireRhombicDodecahedron( void )
904 {
905   int i ;
906   for ( i = 0; i < 12; i++ )
907   {
908     glBegin ( GL_LINE_LOOP ) ;
909       glNormal3dv ( rdod_n[i] ) ;
910       glVertex3dv ( rdod_r[rdod_v[i][0]] ) ;
911       glVertex3dv ( rdod_r[rdod_v[i][1]] ) ;
912       glVertex3dv ( rdod_r[rdod_v[i][2]] ) ;
913       glVertex3dv ( rdod_r[rdod_v[i][3]] ) ;
914     glEnd () ;
915   }
916 }
917
918 /*
919  *
920  */
921 void FGAPIENTRY glutSolidRhombicDodecahedron( void )
922 {
923   int i ;
924
925   glBegin ( GL_QUADS ) ;
926   for ( i = 0; i < 12; i++ )
927   {
928       glNormal3dv ( rdod_n[i] ) ;
929       glVertex3dv ( rdod_r[rdod_v[i][0]] ) ;
930       glVertex3dv ( rdod_r[rdod_v[i][1]] ) ;
931       glVertex3dv ( rdod_r[rdod_v[i][2]] ) ;
932       glVertex3dv ( rdod_r[rdod_v[i][3]] ) ;
933   }
934
935   glEnd () ;
936 }
937
938 #define NUM_FACES     4
939
940 static GLdouble tetrahedron_v[4][3] =  /* Vertices */
941 {
942   { -0.5, -0.288675134595, -0.144337567297 },
943   {  0.5, -0.288675134595, -0.144337567297 },
944   {  0.0,  0.577350269189, -0.144337567297 },
945   {  0.0,  0.0,             0.672159013631 }
946 } ;
947
948 static GLint tetrahedron_i[4][3] =  /* Vertex indices */
949 {
950   { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 1 }, { 1, 3, 2 }
951 } ;
952
953 static GLdouble tetrahedron_n[4][3] =  /* Normals */
954 {
955   {  0.0,             0.0,            -1.0 },
956   { -0.816496580928,  0.471404520791,  0.333333333333 },
957   {  0.0,            -0.942809041582,  0.333333333333 },
958   {  0.816496580928,  0.471404520791,  0.333333333333 }
959 } ;
960
961 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale )
962 {
963   int i, j ;
964
965   if ( num_levels == 0 )
966   {
967
968     for ( i = 0 ; i < NUM_FACES ; i++ )
969     {
970       glBegin ( GL_LINE_LOOP ) ;
971       glNormal3dv ( tetrahedron_n[i] ) ;
972       for ( j = 0; j < 3; j++ )
973       {
974         double x = offset[0] + scale * tetrahedron_v[tetrahedron_i[i][j]][0] ;
975         double y = offset[1] + scale * tetrahedron_v[tetrahedron_i[i][j]][1] ;
976         double z = offset[2] + scale * tetrahedron_v[tetrahedron_i[i][j]][2] ;
977         glVertex3d ( x, y, z ) ;
978       }
979
980       glEnd () ;
981     }
982   }
983   else
984   {
985     GLdouble local_offset[3] ;  /* Use a local variable to avoid buildup of roundoff errors */
986     num_levels -- ;
987     scale /= 2.0 ;
988     local_offset[0] = offset[0] + scale * tetrahedron_v[0][0] ;
989     local_offset[1] = offset[1] + scale * tetrahedron_v[0][1] ;
990     local_offset[2] = offset[2] + scale * tetrahedron_v[0][2] ;
991     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
992     local_offset[0] += scale ;
993     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
994     local_offset[0] -= 0.5            * scale ;
995     local_offset[1] += 0.866025403784 * scale ;
996     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
997     local_offset[1] -= 0.577350269189 * scale ;
998     local_offset[2] += 0.816496580928 * scale ;
999     glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
1000   }
1001 }
1002
1003 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale )
1004 {
1005   int i, j ;
1006
1007   if ( num_levels == 0 )
1008   {
1009     glBegin ( GL_TRIANGLES ) ;
1010
1011     for ( i = 0 ; i < NUM_FACES ; i++ )
1012     {
1013       glNormal3dv ( tetrahedron_n[i] ) ;
1014       for ( j = 0; j < 3; j++ )
1015       {
1016         double x = offset[0] + scale * tetrahedron_v[tetrahedron_i[i][j]][0] ;
1017         double y = offset[1] + scale * tetrahedron_v[tetrahedron_i[i][j]][1] ;
1018         double z = offset[2] + scale * tetrahedron_v[tetrahedron_i[i][j]][2] ;
1019         glVertex3d ( x, y, z ) ;
1020       }
1021     }
1022
1023     glEnd () ;
1024   }
1025   else
1026   {
1027     GLdouble local_offset[3] ;  /* Use a local variable to avoid buildup of roundoff errors */
1028     num_levels -- ;
1029     scale /= 2.0 ;
1030     local_offset[0] = offset[0] + scale * tetrahedron_v[0][0] ;
1031     local_offset[1] = offset[1] + scale * tetrahedron_v[0][1] ;
1032     local_offset[2] = offset[2] + scale * tetrahedron_v[0][2] ;
1033     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1034     local_offset[0] += scale ;
1035     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1036     local_offset[0] -= 0.5            * scale ;
1037     local_offset[1] += 0.866025403784 * scale ;
1038     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1039     local_offset[1] -= 0.577350269189 * scale ;
1040     local_offset[2] += 0.816496580928 * scale ;
1041     glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
1042   }
1043 }
1044
1045 #undef NUM_FACES
1046
1047 /*** END OF FILE ***/