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