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