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