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