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