glutCones now refreshed too
[freeglut] / src / fg_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 #include <GL/freeglut.h>
29 #include "fg_internal.h"
30 #include "fg_gl2.h"
31 #include <math.h>
32
33 /*
34  * Need more types of polyhedra? See CPolyhedron in MRPT
35  */
36
37
38 /* General functions for drawing geometry
39  * Solids are drawn by glDrawArrays if composed of triangles, or by
40  * glDrawElements if consisting of squares or pentagons that were
41  * decomposed into triangles (some vertices are repeated in that case).
42  * WireFrame drawing will have to be done per face, using GL_LINE_LOOP and
43  * issuing one draw call per face. Always use glDrawArrays as no triangle
44  * decomposition needed. We use the "first" parameter in glDrawArrays to go
45  * from face to face.
46  */
47
48 /* Version for OpenGL (ES) 1.1 */
49 #ifndef GL_ES_VERSION_2_0
50 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals, GLsizei numFaces, GLsizei numEdgePerFace)
51 {
52     int i;
53     
54     glEnableClientState(GL_VERTEX_ARRAY);
55     glEnableClientState(GL_NORMAL_ARRAY);
56
57     glVertexPointer(3, GL_FLOAT, 0, vertices);
58     glNormalPointer(GL_FLOAT, 0, normals);
59
60     /* Draw per face (TODO: could use glMultiDrawArrays if available) */
61     for (i=0; i<numFaces; i++)
62         glDrawArrays(GL_LINE_LOOP, i*numEdgePerFace, numEdgePerFace);
63
64     glDisableClientState(GL_VERTEX_ARRAY);
65     glDisableClientState(GL_NORMAL_ARRAY);
66 }
67 #endif
68
69 /* Version for OpenGL (ES) >= 2.0 */
70 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numFaces, GLsizei numEdgePerFace,
71                                   GLint attribute_v_coord, GLint attribute_v_normal)
72 {
73     GLuint vbo_coords = 0, vbo_normals = 0;
74     GLuint numVertices = numFaces * numEdgePerFace;
75
76     int i;
77
78     if (numVertices > 0 && attribute_v_coord != -1) {
79         fghGenBuffers(1, &vbo_coords);
80         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
81         fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
82                       vertices, FGH_STATIC_DRAW);
83     }
84     
85     if (numVertices > 0 && attribute_v_normal != -1) {
86         fghGenBuffers(1, &vbo_normals);
87         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
88         fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
89                       normals, FGH_STATIC_DRAW);
90     }
91     
92     if (vbo_coords) {
93         fghEnableVertexAttribArray(attribute_v_coord);
94         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
95         fghVertexAttribPointer(
96             attribute_v_coord,  /* attribute */
97             3,                  /* number of elements per vertex, here (x,y,z) */
98             GL_FLOAT,           /* the type of each element */
99             GL_FALSE,           /* take our values as-is */
100             0,                  /* no extra data between each position */
101             0                   /* offset of first element */
102         );
103     }
104
105     if (vbo_normals) {
106         fghEnableVertexAttribArray(attribute_v_normal);
107         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
108         fghVertexAttribPointer(
109             attribute_v_normal, /* attribute */
110             3,                  /* number of elements per vertex, here (x,y,z) */
111             GL_FLOAT,           /* the type of each element */
112             GL_FALSE,           /* take our values as-is */
113             0,                  /* no extra data between each position */
114             0                   /* offset of first element */
115         );
116     }
117
118     /* Draw per face (TODO: could use glMultiDrawArrays if available) */
119     for (i=0; i<numFaces; i++)
120         glDrawArrays(GL_LINE_LOOP, i*numEdgePerFace, numEdgePerFace);
121     
122     
123     if (vbo_coords != 0)
124         fghDisableVertexAttribArray(attribute_v_coord);
125     if (vbo_normals != 0)
126         fghDisableVertexAttribArray(attribute_v_normal);
127     
128     if (vbo_coords != 0)
129         fghDeleteBuffers(1, &vbo_coords);
130     if (vbo_normals != 0)
131         fghDeleteBuffers(1, &vbo_normals);
132 }
133
134 static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numFaces, GLsizei numEdgePerFace)
135 {
136     GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
137     GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
138
139     if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
140         /* User requested a 2.0 draw */
141         fghDrawGeometryWire20(vertices, normals, numFaces, numEdgePerFace,
142                           attribute_v_coord, attribute_v_normal);
143 #ifndef GL_ES_VERSION_2_0
144     else
145         fghDrawGeometryWire11(vertices, normals, numFaces, numEdgePerFace);
146 #endif
147 }
148
149
150 /* Draw the geometric shape with filled triangles
151  *
152  * - If the shape is naturally triangulated (numEdgePerFace==3), each
153  *   vertex+normal pair is used only once, so no vertex indices.
154  * 
155  * - If the shape was triangulated (DECOMPOSE_TO_TRIANGLE), some
156  *   vertex+normal pairs are reused, so use vertex indices.
157  */
158
159 /* Version for OpenGL (ES) 1.1 */
160 #ifndef GL_ES_VERSION_2_0
161 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLubyte *vertIdxs,
162                                    GLsizei numVertices, GLsizei numVertIdxs)
163 {
164     glEnableClientState(GL_VERTEX_ARRAY);
165     glEnableClientState(GL_NORMAL_ARRAY);
166
167     glVertexPointer(3, GL_FLOAT, 0, vertices);
168     glNormalPointer(GL_FLOAT, 0, normals);
169     if (vertIdxs == NULL)
170         glDrawArrays(GL_TRIANGLES, 0, numVertices);
171     else
172         glDrawElements(GL_TRIANGLES, numVertIdxs, GL_UNSIGNED_BYTE, vertIdxs);
173
174     glDisableClientState(GL_VERTEX_ARRAY);
175     glDisableClientState(GL_NORMAL_ARRAY);
176 }
177 #endif
178
179 /* Version for OpenGL (ES) >= 2.0 */
180 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLubyte *vertIdxs,
181                                    GLsizei numVertices, GLsizei numVertIdxs,
182                                    GLint attribute_v_coord, GLint attribute_v_normal)
183 {
184     GLuint vbo_coords = 0, vbo_normals = 0, ibo_elements = 0;
185     
186     if (numVertices > 0 && attribute_v_coord != -1) {
187         fghGenBuffers(1, &vbo_coords);
188         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
189         fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
190                       vertices, FGH_STATIC_DRAW);
191     }
192     
193     if (numVertices > 0 && attribute_v_normal != -1) {
194         fghGenBuffers(1, &vbo_normals);
195         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
196         fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
197                       normals, FGH_STATIC_DRAW);
198     }
199     
200     if (vertIdxs != NULL) {
201         fghGenBuffers(1, &ibo_elements);
202         fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
203         fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
204                       vertIdxs, FGH_STATIC_DRAW);
205     }
206     
207     if (vbo_coords) {
208         fghEnableVertexAttribArray(attribute_v_coord);
209         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
210         fghVertexAttribPointer(
211             attribute_v_coord,  /* attribute */
212             3,                  /* number of elements per vertex, here (x,y,z) */
213             GL_FLOAT,           /* the type of each element */
214             GL_FALSE,           /* take our values as-is */
215             0,                  /* no extra data between each position */
216             0                   /* offset of first element */
217         );
218     };
219     
220     if (vbo_normals) {
221         fghEnableVertexAttribArray(attribute_v_normal);
222         fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
223         fghVertexAttribPointer(
224             attribute_v_normal, /* attribute */
225             3,                  /* number of elements per vertex, here (x,y,z) */
226             GL_FLOAT,           /* the type of each element */
227             GL_FALSE,           /* take our values as-is */
228             0,                  /* no extra data between each position */
229             0                   /* offset of first element */
230         );
231     };
232     
233     if (vertIdxs == NULL) {
234         glDrawArrays(GL_TRIANGLES, 0, numVertices);
235     } else {
236         fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
237         glDrawElements(GL_TRIANGLES, numVertIdxs, GL_UNSIGNED_BYTE, 0);
238     }
239     
240     if (vbo_coords != 0)
241         fghDisableVertexAttribArray(attribute_v_coord);
242     if (vbo_normals != 0)
243         fghDisableVertexAttribArray(attribute_v_normal);
244     
245     if (vbo_coords != 0)
246         fghDeleteBuffers(1, &vbo_coords);
247     if (vbo_normals != 0)
248         fghDeleteBuffers(1, &vbo_normals);
249     if (ibo_elements != 0)
250         fghDeleteBuffers(1, &ibo_elements);
251 }
252
253 static void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLubyte *vertIdxs,
254                                  GLsizei numVertices, GLsizei numVertIdxs)
255 {
256     GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
257     GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
258
259     if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
260         /* User requested a 2.0 draw */
261         fghDrawGeometrySolid20(vertices, normals, vertIdxs,
262                                numVertices, numVertIdxs,
263                                attribute_v_coord, attribute_v_normal);
264 #ifndef GL_ES_VERSION_2_0
265     else
266         fghDrawGeometrySolid11(vertices, normals, vertIdxs,
267                                numVertices, numVertIdxs);
268 #endif
269 }
270
271 /* Shape decomposition to triangles
272  * We'll use glDrawElements to draw all shapes that are not naturally
273  * composed of triangles, so generate an index vector here, using the
274  * below sampling scheme.
275  * Be careful to keep winding of all triangles counter-clockwise,
276  * assuming that input has correct winding...
277  */
278 static GLubyte   vert4Decomp[6] = {0,1,2, 0,2,3};             /* quad    : 4 input vertices, 6 output (2 triangles) */
279 static GLubyte   vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3};      /* pentagon: 5 input vertices, 9 output (3 triangles) */
280
281 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLubyte *vertIdxOut)
282 {
283     int i,j,numEdgeIdxPerFace;
284     GLubyte   *vertSamps = NULL;
285     switch (numEdgePerFace)
286     {
287     case 3:
288         /* nothing to do here, we'll draw with glDrawArrays */
289         break;
290     case 4:
291         vertSamps = vert4Decomp;
292         numEdgeIdxPerFace = 6;      /* 6 output vertices for each face */
293         break;
294     case 5:
295         vertSamps = vert5Decomp;
296         numEdgeIdxPerFace = 9;      /* 9 output vertices for each face */
297         break;
298     }
299     /*
300      * Build array with vertices using vertex coordinates and vertex indices
301      * Do same for normals.
302      * Need to do this because of different normals at shared vertices.
303      */
304     for (i=0; i<numFaces; i++)
305     {
306         int normIdx         = i*3;
307         int faceIdxVertIdx  = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
308         for (j=0; j<numEdgePerFace; j++)
309         {
310             int outIdx  = i*numEdgePerFace*3+j*3;
311             int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
312
313             vertOut[outIdx  ] = vertices[vertIdx  ];
314             vertOut[outIdx+1] = vertices[vertIdx+1];
315             vertOut[outIdx+2] = vertices[vertIdx+2];
316
317             normOut[outIdx  ] = normals [normIdx  ];
318             normOut[outIdx+1] = normals [normIdx+1];
319             normOut[outIdx+2] = normals [normIdx+2];
320         }
321
322         /* generate vertex indices for each face */
323         if (vertSamps)
324             for (j=0; j<numEdgeIdxPerFace; j++)
325                 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
326     }
327 }
328
329 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
330 {
331     /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
332     fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
333 }
334
335
336 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
337 /* -- stuff that can be cached -- */
338 /* Cache of input to glDrawArrays or glDrawElements
339  * In general, we build arrays with all vertices or normals.
340  * We cant compress this and use glDrawElements as all combinations of
341  * vertices and normals are unique.
342  */
343 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
344     static GLboolean name##Cached = FALSE;\
345     static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
346     static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
347     static void fgh##nameICaps##Generate()\
348     {\
349         fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
350                             name##_v, name##_vi, name##_n,\
351                             name##_verts, name##_norms);\
352     }
353 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
354     static GLboolean name##Cached = FALSE;\
355     static GLfloat  name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
356     static GLfloat  name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
357     static GLubyte   name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
358     static void fgh##nameICaps##Generate()\
359     {\
360         fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
361                                           name##_v, name##_vi, name##_n,\
362                                           name##_verts, name##_norms, name##_vertIdxs);\
363     }
364
365 /* -- Cube -- */
366 #define CUBE_NUM_VERT           8
367 #define CUBE_NUM_FACES          6
368 #define CUBE_NUM_EDGE_PER_FACE  4
369 #define CUBE_VERT_PER_OBJ       (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
370 #define CUBE_VERT_ELEM_PER_OBJ  (CUBE_VERT_PER_OBJ*3)
371 #define CUBE_VERT_PER_OBJ_TRI   (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2)    /* 2 extra edges per face when drawing quads as triangles */
372 /* Vertex Coordinates */
373 static GLfloat cube_v[CUBE_NUM_VERT*3] =
374 {
375      .5f, .5f, .5f,
376     -.5f, .5f, .5f,
377     -.5f,-.5f, .5f,
378      .5f,-.5f, .5f,
379      .5f,-.5f,-.5f,
380      .5f, .5f,-.5f,
381     -.5f, .5f,-.5f,
382     -.5f,-.5f,-.5f
383 };
384 /* Normal Vectors */
385 static GLfloat cube_n[CUBE_NUM_FACES*3] =
386 {
387      0.0f, 0.0f, 1.0f,
388      1.0f, 0.0f, 0.0f,
389      0.0f, 1.0f, 0.0f,
390     -1.0f, 0.0f, 0.0f,
391      0.0f,-1.0f, 0.0f,
392      0.0f, 0.0f,-1.0f
393 };
394
395 /* Vertex indices, as quads, before triangulation */
396 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
397 {
398     0,1,2,3,
399     0,3,4,5,
400     0,5,6,1,
401     1,6,7,2,
402     7,4,3,2,
403     4,7,6,5
404 };
405 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
406
407 /* -- Dodecahedron -- */
408 /* Magic Numbers:  It is possible to create a dodecahedron by attaching two
409  * pentagons to each face of of a cube. The coordinates of the points are:
410  *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
411  * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
412  *       x = 0.61803398875 and z = 1.61803398875.
413  */
414 #define DODECAHEDRON_NUM_VERT           20
415 #define DODECAHEDRON_NUM_FACES          12
416 #define DODECAHEDRON_NUM_EDGE_PER_FACE  5
417 #define DODECAHEDRON_VERT_PER_OBJ       (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
418 #define DODECAHEDRON_VERT_ELEM_PER_OBJ  (DODECAHEDRON_VERT_PER_OBJ*3)
419 #define DODECAHEDRON_VERT_PER_OBJ_TRI   (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4)    /* 4 extra edges per face when drawing pentagons as triangles */
420 /* Vertex Coordinates */
421 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
422 {
423                0.0f,  1.61803398875f,  0.61803398875f,
424     -          1.0f,            1.0f,            1.0f,
425     -0.61803398875f,            0.0f,  1.61803398875f,
426      0.61803398875f,            0.0f,  1.61803398875f,
427                1.0f,            1.0f,            1.0f,
428                0.0f,  1.61803398875f, -0.61803398875f,
429                1.0f,            1.0f, -          1.0f,
430      0.61803398875f,            0.0f, -1.61803398875f,
431     -0.61803398875f,            0.0f, -1.61803398875f,
432     -          1.0f,            1.0f, -          1.0f,
433                0.0f, -1.61803398875f,  0.61803398875f,
434                1.0f, -          1.0f,            1.0f,
435     -          1.0f, -          1.0f,            1.0f,
436                0.0f, -1.61803398875f, -0.61803398875f,
437     -          1.0f, -          1.0f, -          1.0f,
438                1.0f, -          1.0f, -          1.0f,
439      1.61803398875f, -0.61803398875f,            0.0f,
440      1.61803398875f,  0.61803398875f,            0.0f,
441     -1.61803398875f,  0.61803398875f,            0.0f,
442     -1.61803398875f, -0.61803398875f,            0.0f
443 };
444 /* Normal Vectors */
445 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
446 {
447                 0.0f,  0.525731112119f,  0.850650808354f,
448                 0.0f,  0.525731112119f, -0.850650808354f,
449                 0.0f, -0.525731112119f,  0.850650808354f,
450                 0.0f, -0.525731112119f, -0.850650808354f,
451
452      0.850650808354f,             0.0f,  0.525731112119f,
453     -0.850650808354f,             0.0f,  0.525731112119f,
454      0.850650808354f,             0.0f, -0.525731112119f,
455     -0.850650808354f,             0.0f, -0.525731112119f,
456
457      0.525731112119f,  0.850650808354f,             0.0f,
458      0.525731112119f, -0.850650808354f,             0.0f,
459     -0.525731112119f,  0.850650808354f,             0.0f, 
460     -0.525731112119f, -0.850650808354f,             0.0f,
461 };
462
463 /* Vertex indices */
464 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
465 {
466      0,  1,  2,  3,  4, 
467      5,  6,  7,  8,  9, 
468     10, 11,  3,  2, 12, 
469     13, 14,  8,  7, 15, 
470
471      3, 11, 16, 17,  4, 
472      2,  1, 18, 19, 12, 
473      7,  6, 17, 16, 15, 
474      8, 14, 19, 18,  9, 
475
476     17,  6,  5,  0,  4, 
477     16, 11, 10, 13, 15, 
478     18,  1,  0,  5,  9, 
479     19, 14, 13, 10, 12
480 };
481 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
482
483
484 /* -- Icosahedron -- */
485 #define ICOSAHEDRON_NUM_VERT           12
486 #define ICOSAHEDRON_NUM_FACES          20
487 #define ICOSAHEDRON_NUM_EDGE_PER_FACE  3
488 #define ICOSAHEDRON_VERT_PER_OBJ       (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
489 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ  (ICOSAHEDRON_VERT_PER_OBJ*3)
490 #define ICOSAHEDRON_VERT_PER_OBJ_TRI   ICOSAHEDRON_VERT_PER_OBJ
491 /* Vertex Coordinates */
492 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
493 {
494                 1.0f,             0.0f,             0.0f,
495      0.447213595500f,  0.894427191000f,             0.0f,
496      0.447213595500f,  0.276393202252f,  0.850650808354f,
497      0.447213595500f, -0.723606797748f,  0.525731112119f,
498      0.447213595500f, -0.723606797748f, -0.525731112119f,
499      0.447213595500f,  0.276393202252f, -0.850650808354f,
500     -0.447213595500f, -0.894427191000f,             0.0f,
501     -0.447213595500f, -0.276393202252f,  0.850650808354f,
502     -0.447213595500f,  0.723606797748f,  0.525731112119f,
503     -0.447213595500f,  0.723606797748f, -0.525731112119f,
504     -0.447213595500f, -0.276393202252f, -0.850650808354f,
505     -           1.0f,             0.0f,             0.0f
506 };
507 /* Normal Vectors:
508  * icosahedron_n[i][0] = ( icosahedron_v[icosahedron_vi[i][1]][1] - icosahedron_v[icosahedron_vi[i][0]][1] ) * ( icosahedron_v[icosahedron_vi[i][2]][2] - icosahedron_v[icosahedron_vi[i][0]][2] ) - ( icosahedron_v[icosahedron_vi[i][1]][2] - icosahedron_v[icosahedron_vi[i][0]][2] ) * ( icosahedron_v[icosahedron_vi[i][2]][1] - icosahedron_v[icosahedron_vi[i][0]][1] ) ;
509  * icosahedron_n[i][1] = ( icosahedron_v[icosahedron_vi[i][1]][2] - icosahedron_v[icosahedron_vi[i][0]][2] ) * ( icosahedron_v[icosahedron_vi[i][2]][0] - icosahedron_v[icosahedron_vi[i][0]][0] ) - ( icosahedron_v[icosahedron_vi[i][1]][0] - icosahedron_v[icosahedron_vi[i][0]][0] ) * ( icosahedron_v[icosahedron_vi[i][2]][2] - icosahedron_v[icosahedron_vi[i][0]][2] ) ;
510  * icosahedron_n[i][2] = ( icosahedron_v[icosahedron_vi[i][1]][0] - icosahedron_v[icosahedron_vi[i][0]][0] ) * ( icosahedron_v[icosahedron_vi[i][2]][1] - icosahedron_v[icosahedron_vi[i][0]][1] ) - ( icosahedron_v[icosahedron_vi[i][1]][1] - icosahedron_v[icosahedron_vi[i][0]][1] ) * ( icosahedron_v[icosahedron_vi[i][2]][0] - icosahedron_v[icosahedron_vi[i][0]][0] ) ;
511 */
512 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
513 {
514      0.760845213037948f,  0.470228201835026f,  0.341640786498800f,
515      0.760845213036861f, -0.179611190632978f,  0.552786404500000f,
516      0.760845213033849f, -0.581234022404097f,                0.0f,
517      0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
518      0.760845213037948f,  0.470228201835026f, -0.341640786498800f,
519      0.179611190628666f,  0.760845213037948f,  0.552786404498399f,
520      0.179611190634277f, -0.290617011204044f,  0.894427191000000f,
521      0.179611190633958f, -0.940456403667806f,                0.0f,
522      0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
523      0.179611190628666f,  0.760845213037948f, -0.552786404498399f,
524     -0.179611190633958f,  0.940456403667806f,                0.0f,
525     -0.179611190634277f,  0.290617011204044f,  0.894427191000000f,
526     -0.179611190628666f, -0.760845213037948f,  0.552786404498399f,
527     -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
528     -0.179611190634277f,  0.290617011204044f, -0.894427191000000f,
529     -0.760845213036861f,  0.179611190632978f, -0.552786404500000f,
530     -0.760845213033849f,  0.581234022404097f,                0.0f,
531     -0.760845213036861f,  0.179611190632978f,  0.552786404500000f,
532     -0.760845213037948f, -0.470228201835026f,  0.341640786498800f,
533     -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
534 };
535
536 /* Vertex indices */
537 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
538 {
539     0,   1,  2 ,
540     0,   2,  3 ,
541     0,   3,  4 ,
542     0,   4,  5 ,
543     0,   5,  1 ,
544     1,   8,  2 ,
545     2,   7,  3 ,
546     3,   6,  4 ,
547     4,  10,  5 ,
548     5,   9,  1 ,
549     1,   9,  8 ,
550     2,   8,  7 ,
551     3,   7,  6 ,
552     4,   6, 10 ,
553     5,  10,  9 ,
554     11,  9, 10 ,
555     11,  8,  9 ,
556     11,  7,  8 ,
557     11,  6,  7 ,
558     11, 10,  6 
559 };
560 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
561
562 /* -- Octahedron -- */
563 #define OCTAHEDRON_NUM_VERT           6
564 #define OCTAHEDRON_NUM_FACES          8
565 #define OCTAHEDRON_NUM_EDGE_PER_FACE  3
566 #define OCTAHEDRON_VERT_PER_OBJ       (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
567 #define OCTAHEDRON_VERT_ELEM_PER_OBJ  (OCTAHEDRON_VERT_PER_OBJ*3)
568 #define OCTAHEDRON_VERT_PER_OBJ_TRI   OCTAHEDRON_VERT_PER_OBJ
569
570 /* Vertex Coordinates */
571 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
572 {
573      1.f,  0.f,  0.f,
574      0.f,  1.f,  0.f,
575      0.f,  0.f,  1.f,
576     -1.f,  0.f,  0.f,
577      0.f, -1.f,  0.f,
578      0.f,  0.f, -1.f,
579
580 };
581 /* Normal Vectors */
582 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
583 {
584      0.577350269189f, 0.577350269189f, 0.577350269189f,    /* sqrt(1/3) */
585      0.577350269189f, 0.577350269189f,-0.577350269189f,
586      0.577350269189f,-0.577350269189f, 0.577350269189f,
587      0.577350269189f,-0.577350269189f,-0.577350269189f,
588     -0.577350269189f, 0.577350269189f, 0.577350269189f,
589     -0.577350269189f, 0.577350269189f,-0.577350269189f,
590     -0.577350269189f,-0.577350269189f, 0.577350269189f,
591     -0.577350269189f,-0.577350269189f,-0.577350269189f
592
593 };
594
595 /* Vertex indices */
596 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
597 {
598     0, 1, 2,
599     0, 5, 1,
600     0, 2, 4,
601     0, 4, 5,
602     3, 2, 1,
603     3, 1, 5,
604     3, 4, 2,
605     3, 5, 4
606 };
607 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
608
609 /* -- RhombicDodecahedron -- */
610 #define RHOMBICDODECAHEDRON_NUM_VERT            14
611 #define RHOMBICDODECAHEDRON_NUM_FACES           12
612 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE   4
613 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ       (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
614 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ  (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
615 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI   (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2)    /* 2 extra edges per face when drawing quads as triangles */
616
617 /* Vertex Coordinates */
618 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
619 {
620                 0.0f,             0.0f,  1.0f,
621      0.707106781187f,             0.0f,  0.5f,
622                 0.0f,  0.707106781187f,  0.5f,
623     -0.707106781187f,             0.0f,  0.5f,
624                 0.0f, -0.707106781187f,  0.5f,
625      0.707106781187f,  0.707106781187f,  0.0f,
626     -0.707106781187f,  0.707106781187f,  0.0f,
627     -0.707106781187f, -0.707106781187f,  0.0f,
628      0.707106781187f, -0.707106781187f,  0.0f,
629      0.707106781187f,             0.0f, -0.5f,
630                 0.0f,  0.707106781187f, -0.5f,
631     -0.707106781187f,             0.0f, -0.5f,
632                 0.0f, -0.707106781187f, -0.5f,
633                 0.0f,             0.0f, -1.0f
634 };
635 /* Normal Vectors */
636 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
637 {
638      0.353553390594f,  0.353553390594f,  0.5f,
639     -0.353553390594f,  0.353553390594f,  0.5f,
640     -0.353553390594f, -0.353553390594f,  0.5f,
641      0.353553390594f, -0.353553390594f,  0.5f,
642                 0.0f,             1.0f,  0.0f,
643     -           1.0f,             0.0f,  0.0f,
644                 0.0f, -           1.0f,  0.0f,
645                 1.0f,             0.0f,  0.0f,
646      0.353553390594f,  0.353553390594f, -0.5f,
647     -0.353553390594f,  0.353553390594f, -0.5f,
648     -0.353553390594f, -0.353553390594f, -0.5f,
649      0.353553390594f, -0.353553390594f, -0.5f
650 };
651
652 /* Vertex indices */
653 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
654 {
655     0,  1,  5,  2,
656     0,  2,  6,  3,
657     0,  3,  7,  4,
658     0,  4,  8,  1,
659     5, 10,  6,  2,
660     6, 11,  7,  3,
661     7, 12,  8,  4,
662     8,  9,  5,  1,
663     5,  9, 13, 10,
664     6, 10, 13, 11,
665     7, 11, 13, 12,
666     8, 12, 13,  9
667 };
668 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
669
670 /* -- Tetrahedron -- */
671 /* Magic Numbers:  r0 = ( 1, 0, 0 )
672  *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
673  *                 r2 = ( -1/3, - sqrt(2) / 3,  sqrt(6) / 3 )
674  *                 r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
675  * |r0| = |r1| = |r2| = |r3| = 1
676  * Distance between any two points is 2 sqrt(6) / 3
677  *
678  * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
679  */
680 #define TETRAHEDRON_NUM_VERT            4
681 #define TETRAHEDRON_NUM_FACES           4
682 #define TETRAHEDRON_NUM_EDGE_PER_FACE   3
683 #define TETRAHEDRON_VERT_PER_OBJ        (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
684 #define TETRAHEDRON_VERT_ELEM_PER_OBJ   (TETRAHEDRON_VERT_PER_OBJ*3)
685 #define TETRAHEDRON_VERT_PER_OBJ_TRI    TETRAHEDRON_VERT_PER_OBJ
686
687 /* Vertex Coordinates */
688 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
689 {
690                 1.0f,             0.0f,             0.0f,
691     -0.333333333333f,  0.942809041582f,             0.0f,
692     -0.333333333333f, -0.471404520791f,  0.816496580928f,
693     -0.333333333333f, -0.471404520791f, -0.816496580928f
694 };
695 /* Normal Vectors */
696 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
697 {
698     -           1.0f,             0.0f,             0.0f,
699      0.333333333333f, -0.942809041582f,             0.0f,
700      0.333333333333f,  0.471404520791f, -0.816496580928f,
701      0.333333333333f,  0.471404520791f,  0.816496580928f
702 };
703
704 /* Vertex indices */
705 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
706 {
707     1, 3, 2,
708     0, 2, 3,
709     0, 3, 1,
710     0, 1, 2
711 };
712 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
713
714 /* -- Sierpinski Sponge -- */
715 static unsigned int ipow (int x, unsigned int y)
716 {
717     return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2);
718 }
719
720 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
721 {
722     int i, j;
723     if ( numLevels == 0 )
724     {
725         for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
726         {
727             int normIdx         = i*3;
728             int faceIdxVertIdx  = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
729             for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
730             {
731                 int outIdx  = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
732                 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
733
734                 vertices[outIdx  ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx  ];
735                 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
736                 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
737
738                 normals [outIdx  ] = tetrahedron_n[normIdx  ];
739                 normals [outIdx+1] = tetrahedron_n[normIdx+1];
740                 normals [outIdx+2] = tetrahedron_n[normIdx+2];
741             }
742         }
743     }
744     else if ( numLevels > 0 )
745     {
746         double local_offset[3] ;    /* Use a local variable to avoid buildup of roundoff errors */
747         unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
748         scale /= 2.0 ;
749         for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
750         {
751             int idx         = i*3;
752             local_offset[0] = offset[0] + scale * tetrahedron_v[idx  ];
753             local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
754             local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
755             fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
756         }
757     }
758 }
759
760 #ifndef GL_ES_VERSION_2_0
761 /* -- Now the various shapes involving circles -- */
762 /*
763  * Compute lookup table of cos and sin values forming a circle
764  * (or half circle if halfCircle==TRUE)
765  *
766  * Notes:
767  *    It is the responsibility of the caller to free these tables
768  *    The size of the table is (n+1) to form a connected loop
769  *    The last entry is exactly the same as the first
770  *    The sign of n can be flipped to get the reverse loop
771  */
772 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
773 {
774     int i;
775     
776     /* Table size, the sign of n flips the circle direction */
777     const int size = abs(n);
778
779     /* Determine the angle between samples */
780     const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
781
782     /* Allocate memory for n samples, plus duplicate of first entry at the end */
783     *sint = malloc(sizeof(GLfloat) * (size+1));
784     *cost = malloc(sizeof(GLfloat) * (size+1));
785
786     /* Bail out if memory allocation fails, fgError never returns */
787     if (!(*sint) || !(*cost))
788     {
789         free(*sint);
790         free(*cost);
791         fgError("Failed to allocate memory in fghCircleTable");
792     }
793
794     /* Compute cos and sin around the circle */
795     (*sint)[0] = 0.0;
796     (*cost)[0] = 1.0;
797
798     for (i=1; i<size; i++)
799     {
800 #ifdef __cplusplus
801         (*sint)[i] = sinf(angle*i);
802         (*cost)[i] = cosf(angle*i);
803 #else
804         (*sint)[i] = (float)sin((double)(angle*i));
805         (*cost)[i] = (float)cos((double)(angle*i));
806 #endif  /* __cplusplus */
807     }
808
809     
810     if (halfCircle)
811     {
812         (*sint)[size] =  0.0f;  /* sin PI */
813         (*cost)[size] = -1.0f;  /* cos PI */
814     }
815     else
816     {
817         /* Last sample is duplicate of the first (sin or cos of 2 PI) */
818         (*sint)[size] = (*sint)[0];
819         (*cost)[size] = (*cost)[0];
820     }
821 }
822
823 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
824 {
825     int i,j;
826     int idx = 0;    /* idx into vertex/normal buffer */
827     GLfloat x,y,z;
828
829     /* Pre-computed circle */
830     GLfloat *sint1,*cost1;
831     GLfloat *sint2,*cost2;
832
833     /* number of unique vertices */
834     if (slices==0 || stacks<2)
835     {
836         /* nothing to generate */
837         *nVert = 0;
838         return;
839     }
840     *nVert = slices*(stacks-1)+2;
841
842     /* precompute values on unit circle */
843     fghCircleTable(&sint1,&cost1,-slices,FALSE);
844     fghCircleTable(&sint2,&cost2, stacks,TRUE);
845
846     /* Allocate vertex and normal buffers, bail out if memory allocation fails */
847     *vertices = malloc((*nVert)*3*sizeof(GLfloat));
848     *normals  = malloc((*nVert)*3*sizeof(GLfloat));
849     if (!(vertices) || !(normals))
850     {
851         free(*vertices);
852         free(*normals);
853         fgError("Failed to allocate memory in fghGenerateSphere");
854     }
855
856     /* top */
857     (*vertices)[0] = 0.f;
858     (*vertices)[1] = 0.f;
859     (*vertices)[2] = radius;
860     (*normals )[0] = 0.f;
861     (*normals )[1] = 0.f;
862     (*normals )[2] = 1.f;
863     idx = 3;
864
865     /* each stack */
866     for( i=1; i<stacks; i++ )
867     {
868         for(j=0; j<slices; j++, idx+=3)
869         {
870             x = cost1[j]*sint2[i];
871             y = sint1[j]*sint2[i];
872             z = cost2[i];
873
874             (*vertices)[idx  ] = x*radius;
875             (*vertices)[idx+1] = y*radius;
876             (*vertices)[idx+2] = z*radius;
877             (*normals )[idx  ] = x;
878             (*normals )[idx+1] = y;
879             (*normals )[idx+2] = z;
880         }
881     }
882
883     /* bottom */
884     (*vertices)[idx  ] =  0.f;
885     (*vertices)[idx+1] =  0.f;
886     (*vertices)[idx+2] = -radius;
887     (*normals )[idx  ] =  0.f;
888     (*normals )[idx+1] =  0.f;
889     (*normals )[idx+2] = -1.f;
890
891     /* Done creating vertices, release sin and cos tables */
892     free(sint1);
893     free(cost1);
894     free(sint2);
895     free(cost2);
896 }
897
898 void fghGenerateCone(
899     GLfloat base, GLfloat height, GLint slices, GLint stacks,   /*  input */
900     GLfloat **vertices, GLfloat **normals, int* nVert           /* output */
901     )
902 {
903     int i,j;
904     int idx = 0;    /* idx into vertex/normal buffer */
905
906     /* Pre-computed circle */
907     GLfloat *sint,*cost;
908
909     /* Step in z and radius as stacks are drawn. */
910     GLfloat z = 0;
911     GLfloat r = (GLfloat)base;
912
913     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
914     const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
915
916     /* Scaling factors for vertex normals */
917 #ifdef __cplusplus
918     const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
919     const GLfloat sinn = ( (GLfloat)base   / sqrtf( height * height + base * base ));
920 #else
921     const GLfloat cosn = ( (GLfloat)height / (GLfloat)sqrt( (double)(height * height + base * base) ));
922     const GLfloat sinn = ( (GLfloat)base   / (GLfloat)sqrt( (double)(height * height + base * base) ));
923 #endif  /* __cplusplus */
924
925
926
927     /* number of unique vertices */
928     if (slices==0 || stacks<1)
929     {
930         /* nothing to generate */
931         *nVert = 0;
932         return;
933     }
934     *nVert = slices*(stacks+1)+1;
935
936     /* Pre-computed circle */
937     fghCircleTable(&sint,&cost,-slices,FALSE);
938
939     /* Allocate vertex and normal buffers, bail out if memory allocation fails */
940     *vertices = malloc((*nVert)*3*sizeof(GLfloat));
941     *normals  = malloc((*nVert)*3*sizeof(GLfloat));
942     if (!(vertices) || !(normals))
943     {
944         free(*vertices);
945         free(*normals);
946         fgError("Failed to allocate memory in fghGenerateSphere");
947     }
948
949     /* bottom */
950     (*vertices)[0] =  0.f;
951     (*vertices)[1] =  0.f;
952     (*vertices)[2] =  z;
953     (*normals )[0] =  0.f;
954     (*normals )[1] =  0.f;
955     (*normals )[2] = -1.f;
956     idx = 3;
957
958     /* each stack */
959     for (i=0; i<stacks+1; i++ )
960     {
961         for (j=0; j<slices; j++, idx+=3)
962         {
963             (*vertices)[idx  ] = cost[j]*r;
964             (*vertices)[idx+1] = sint[j]*r;
965             (*vertices)[idx+2] = z;
966             (*normals )[idx  ] = cost[j]*sinn;
967             (*normals )[idx+1] = sint[j]*sinn;
968             (*normals )[idx+2] = cosn;
969         }
970
971         z += zStep;
972         r -= rStep;
973     }
974
975     /* Release sin and cos tables */
976     free(sint);
977     free(cost);
978 }
979 #endif
980
981 /* -- INTERNAL DRAWING functions --------------------------------------- */
982 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
983     static void fgh##nameICaps( GLboolean useWireMode )\
984     {\
985         if (!name##Cached)\
986         {\
987             fgh##nameICaps##Generate();\
988             name##Cached = GL_TRUE;\
989         }\
990         \
991         if (useWireMode)\
992         {\
993             fghDrawGeometryWire (name##_verts,name##_norms,\
994                                                              nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE);\
995         }\
996         else\
997         {\
998             fghDrawGeometrySolid(name##_verts,name##_norms,vertIdxs,\
999                                  nameCaps##_VERT_PER_OBJ, nameCaps##_VERT_PER_OBJ_TRI); \
1000         }\
1001     }
1002 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps)                        _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1003 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1004
1005 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1006 {
1007     GLfloat *vertices;
1008
1009     if (!cubeCached)
1010     {
1011         fghCubeGenerate();
1012         cubeCached = GL_TRUE;
1013     }
1014
1015     if (dSize!=1.f)
1016     {
1017         /* Need to build new vertex list containing vertices for cube of different size */
1018         int i;
1019
1020         vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1021
1022         /* Bail out if memory allocation fails, fgError never returns */
1023         if (!vertices)
1024         {
1025             free(vertices);
1026             fgError("Failed to allocate memory in fghCube");
1027         }
1028
1029         for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1030             vertices[i] = dSize*cube_verts[i];
1031     }
1032     else
1033         vertices = cube_verts;
1034
1035     if (useWireMode)
1036         fghDrawGeometryWire(vertices, cube_norms,
1037                             CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE);
1038     else
1039         fghDrawGeometrySolid(vertices, cube_norms, cube_vertIdxs,
1040                              CUBE_VERT_PER_OBJ, CUBE_VERT_PER_OBJ_TRI);
1041
1042     if (dSize!=1.f)
1043         /* cleanup allocated memory */
1044         free(vertices);
1045 }
1046
1047 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1048 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1049 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1050 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1051 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1052
1053 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1054 {
1055     GLfloat *vertices;
1056     GLfloat * normals;
1057     GLsizei    numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1058     GLsizei    numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1059     GLsizei    numFace = numTetr*TETRAHEDRON_NUM_FACES;
1060
1061     if (numTetr)
1062     {
1063         /* Allocate memory */
1064         vertices = malloc(numVert*3 * sizeof(GLfloat));
1065         normals  = malloc(numVert*3 * sizeof(GLfloat));
1066         /* Bail out if memory allocation fails, fgError never returns */
1067         if (!vertices || !normals)
1068         {
1069             free(vertices);
1070             free(normals);
1071             fgError("Failed to allocate memory in fghSierpinskiSponge");
1072         }
1073
1074         /* Generate elements */
1075         fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1076
1077         /* Draw and cleanup */
1078         if (useWireMode)
1079             fghDrawGeometryWire (vertices,normals,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE);
1080         else
1081             fghDrawGeometrySolid(vertices,normals,NULL,numVert,numVert);
1082
1083         free(vertices);
1084         free(normals );
1085     }
1086 }
1087
1088
1089 #ifndef GL_ES_VERSION_2_0
1090 static void fghSphere( double radius, GLint slices, GLint stacks, GLboolean useWireMode )
1091 {
1092     int i,j,idx, nVert;
1093     GLfloat *vertices, *normals;
1094
1095     if (slices * stacks > 65535)
1096         fgWarning("fghSphere: too many slices or stacks requested, indices will wrap");
1097
1098     /* Generate vertices and normals */
1099     fghGenerateSphere((GLfloat)radius,slices,stacks,&vertices,&normals,&nVert);
1100     
1101     if (nVert==0)
1102         /* nothing to draw */
1103         return;
1104
1105     if (useWireMode)
1106     {
1107         GLushort  *sliceIdx, *stackIdx;
1108         /* First, generate vertex index arrays for drawing with glDrawElements
1109          * We have a bunch of line_loops to draw for each stack, and a
1110          * bunch for each slice.
1111          */
1112
1113         sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1114         stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1115         if (!(stackIdx) || !(sliceIdx))
1116         {
1117             free(stackIdx);
1118             free(sliceIdx);
1119             fgError("Failed to allocate memory in fghGenerateSphere");
1120         }
1121
1122         /* generate for each stack */
1123         for (i=0,idx=0; i<stacks-1; i++)
1124         {
1125             GLushort offset = 1+i*slices;           /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1126             for (j=0; j<slices; j++, idx++)
1127             {
1128                 stackIdx[idx] = offset+j;
1129             }
1130         }
1131
1132         /* generate for each slice */
1133         for (i=0,idx=0; i<slices; i++)
1134         {
1135             GLushort offset = 1+i;                  /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1136             sliceIdx[idx++] = 0;                    /* vertex on top */
1137             for (j=0; j<stacks-1; j++, idx++)
1138             {
1139                 sliceIdx[idx] = offset+j*slices;
1140             }
1141             sliceIdx[idx++] = nVert-1;              /* zero based index, last element in array... */
1142         }
1143
1144         /* draw */
1145         glEnableClientState(GL_VERTEX_ARRAY);
1146         glEnableClientState(GL_NORMAL_ARRAY);
1147
1148         glVertexPointer(3, GL_FLOAT, 0, vertices);
1149         glNormalPointer(GL_FLOAT, 0, normals);
1150         /*draw slices*/
1151         for (i=0; i<slices; i++)
1152             glDrawElements(GL_LINE_STRIP,stacks+1,GL_UNSIGNED_SHORT,sliceIdx+i*(stacks+1));
1153         /*draw stacks*/
1154         for (i=0; i<stacks-1; i++)
1155             glDrawElements(GL_LINE_LOOP, slices,GL_UNSIGNED_SHORT,stackIdx+i*slices);
1156
1157         glDisableClientState(GL_VERTEX_ARRAY);
1158         glDisableClientState(GL_NORMAL_ARRAY);
1159
1160         /* cleanup allocated memory */
1161         free(sliceIdx);
1162         free(stackIdx);
1163     }
1164     else
1165     {
1166         /* First, generate vertex index arrays for drawing with glDrawElements
1167          * All stacks, including top and bottom are covered with a triangle
1168          * strip.
1169          */
1170         GLushort  *stripIdx;
1171         /* Create index vector */
1172         GLushort offset;
1173
1174         /* Allocate buffers for indices, bail out if memory allocation fails */
1175         stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1176         if (!(stripIdx))
1177         {
1178             free(stripIdx);
1179             fgError("Failed to allocate memory in fghGenerateSphere");
1180         }
1181
1182         /* top stack */
1183         for (j=0, idx=0;  j<slices;  j++, idx+=2)
1184         {
1185             stripIdx[idx  ] = j+1;              /* 0 is top vertex, 1 is first for first stack */
1186             stripIdx[idx+1] = 0;
1187         }
1188         stripIdx[idx  ] = 1;                    /* repeat first slice's idx for closing off shape */
1189         stripIdx[idx+1] = 0;
1190         idx+=2;
1191
1192         /* middle stacks: */
1193         /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1194         for (i=0; i<stacks-2; i++, idx+=2)
1195         {
1196             offset = 1+i*slices;                    /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1197             for (j=0; j<slices; j++, idx+=2)
1198             {
1199                 stripIdx[idx  ] = offset+j+slices;
1200                 stripIdx[idx+1] = offset+j;
1201             }
1202             stripIdx[idx  ] = offset+slices;        /* repeat first slice's idx for closing off shape */
1203             stripIdx[idx+1] = offset;
1204         }
1205
1206         /* bottom stack */
1207         offset = 1+(stacks-2)*slices;               /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1208         for (j=0; j<slices; j++, idx+=2)
1209         {
1210             stripIdx[idx  ] = nVert-1;              /* zero based index, last element in array (bottom vertex)... */
1211             stripIdx[idx+1] = offset+j;
1212         }
1213         stripIdx[idx  ] = nVert-1;                  /* repeat first slice's idx for closing off shape */
1214         stripIdx[idx+1] = offset;
1215
1216
1217         /* draw */
1218         glEnableClientState(GL_VERTEX_ARRAY);
1219         glEnableClientState(GL_NORMAL_ARRAY);
1220
1221         glVertexPointer(3, GL_FLOAT, 0, vertices);
1222         glNormalPointer(GL_FLOAT, 0, normals);
1223         /*draw stacks*/
1224         for (i=0; i<stacks; i++)
1225             glDrawElements(GL_TRIANGLE_STRIP,(slices+1)*2,GL_UNSIGNED_SHORT,stripIdx+i*(slices+1)*2);
1226
1227         glDisableClientState(GL_VERTEX_ARRAY);
1228         glDisableClientState(GL_NORMAL_ARRAY);
1229
1230         /* cleanup allocated memory */
1231         free(stripIdx);
1232     }
1233     
1234     /* cleanup allocated memory */
1235     free(vertices);
1236     free(normals);
1237 }
1238
1239 static void fghCone( double base, double height, GLint slices, GLint stacks, GLboolean useWireMode )
1240 {
1241     int i,j,idx, nVert;
1242     GLfloat *vertices, *normals;
1243
1244     if (slices * stacks > 65535)
1245         fgWarning("fghCone: too many slices or stacks requested, indices will wrap");
1246
1247     /* Generate vertices and normals */
1248     fghGenerateCone((GLfloat)base,(GLfloat)height,slices,stacks,&vertices,&normals,&nVert);
1249
1250     if (nVert==0)
1251         /* nothing to draw */
1252         return;
1253
1254     if (useWireMode)
1255     {
1256         GLushort  *sliceIdx, *stackIdx;
1257         /* First, generate vertex index arrays for drawing with glDrawElements
1258          * We have a bunch of line_loops to draw for each stack, and a
1259          * bunch for each slice.
1260          */
1261
1262         stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1263         sliceIdx = malloc(slices*2         *sizeof(GLushort));
1264         if (!(stackIdx) || !(sliceIdx))
1265         {
1266             free(stackIdx);
1267             free(sliceIdx);
1268             fgError("Failed to allocate memory in fghGenerateCone");
1269         }
1270
1271         /* generate for each stack */
1272         for (i=0,idx=0; i<stacks+1; i++)
1273         {
1274             GLushort offset = 1+i*slices;           /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1275             for (j=0; j<slices; j++, idx++)
1276             {
1277                 stackIdx[idx] = offset+j;
1278             }
1279         }
1280
1281         /* generate for each slice */
1282         for (i=0,idx=0; i<slices; i++)
1283         {
1284             GLushort offset = 1+i;                  /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1285             sliceIdx[idx++] = offset;
1286             sliceIdx[idx++] = offset+stacks*slices;
1287         }
1288
1289         /* draw */
1290         glEnableClientState(GL_VERTEX_ARRAY);
1291         glEnableClientState(GL_NORMAL_ARRAY);
1292
1293         glVertexPointer(3, GL_FLOAT, 0, vertices);
1294         glNormalPointer(GL_FLOAT, 0, normals);
1295         /*draw slices*/
1296         glDrawElements(GL_LINES,slices*2,GL_UNSIGNED_SHORT,sliceIdx);
1297         /*draw stacks*/
1298         for (i=0; i<stacks; i++)
1299             glDrawElements(GL_LINE_LOOP, slices,GL_UNSIGNED_SHORT,stackIdx+i*slices);
1300
1301         glDisableClientState(GL_VERTEX_ARRAY);
1302         glDisableClientState(GL_NORMAL_ARRAY);
1303
1304         /* cleanup allocated memory */
1305         free(sliceIdx);
1306         free(stackIdx);
1307     }
1308     else
1309     {
1310         /* First, generate vertex index arrays for drawing with glDrawElements
1311          * All stacks, including top and bottom are covered with a triangle
1312          * strip.
1313          */
1314         GLushort  *stripIdx;
1315         /* Create index vector */
1316         GLushort offset;
1317
1318         /* Allocate buffers for indices, bail out if memory allocation fails */
1319         stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort));
1320         if (!(stripIdx))
1321         {
1322             free(stripIdx);
1323             fgError("Failed to allocate memory in fghGenerateCone");
1324         }
1325
1326         /* top stack */
1327         for (j=0, idx=0;  j<slices;  j++, idx+=2)
1328         {
1329             stripIdx[idx  ] = 0;
1330             stripIdx[idx+1] = j+1;              /* 0 is top vertex, 1 is first for first stack */
1331         }
1332         stripIdx[idx  ] = 0;                    /* repeat first slice's idx for closing off shape */
1333         stripIdx[idx+1] = 1;
1334         idx+=2;
1335
1336         /* middle stacks: */
1337         /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1338         for (i=0; i<stacks; i++, idx+=2)
1339         {
1340             offset = 1+i*slices;                    /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1341             for (j=0; j<slices; j++, idx+=2)
1342             {
1343                 stripIdx[idx  ] = offset+j;
1344                 stripIdx[idx+1] = offset+j+slices;
1345             }
1346             stripIdx[idx  ] = offset;               /* repeat first slice's idx for closing off shape */
1347             stripIdx[idx+1] = offset+slices;
1348         }
1349
1350         /* draw */
1351         glEnableClientState(GL_VERTEX_ARRAY);
1352         glEnableClientState(GL_NORMAL_ARRAY);
1353
1354         glVertexPointer(3, GL_FLOAT, 0, vertices);
1355         glNormalPointer(GL_FLOAT, 0, normals);
1356         /*draw stacks*/
1357         for (i=0; i<stacks+1; i++)
1358             glDrawElements(GL_TRIANGLE_STRIP,(slices+1)*2,GL_UNSIGNED_SHORT,stripIdx+i*(slices+1)*2);
1359
1360         glDisableClientState(GL_VERTEX_ARRAY);
1361         glDisableClientState(GL_NORMAL_ARRAY);
1362
1363         /* cleanup allocated memory */
1364         free(stripIdx);
1365     }
1366
1367     /* cleanup allocated memory */
1368     free(vertices);
1369     free(normals);
1370 }
1371
1372
1373 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
1374
1375
1376 /*
1377  * Draws a solid sphere
1378  */
1379 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
1380 {
1381     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
1382
1383     fghSphere( radius, slices, stacks, FALSE );
1384 }
1385
1386 /*
1387  * Draws a wire sphere
1388  */
1389 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
1390 {
1391     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
1392
1393     fghSphere( radius, slices, stacks, TRUE );
1394     
1395 }
1396 #endif /* GL_ES_VERSION_2_0 */
1397
1398 #ifndef EGL_VERSION_1_0
1399 /*
1400  * Draws a solid cone
1401  */
1402 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
1403 {
1404     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
1405
1406     fghCone( base, height, slices, stacks, FALSE );
1407 }
1408
1409 /*
1410  * Draws a wire cone
1411  */
1412 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
1413 {
1414     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
1415
1416     fghCone( base, height, slices, stacks, TRUE );
1417 }
1418
1419
1420 /*
1421  * Draws a solid cylinder
1422  */
1423 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
1424 {
1425     int i,j;
1426
1427     /* Step in z and radius as stacks are drawn. */
1428     GLfloat radf = (GLfloat)radius;
1429     GLfloat z0,z1;
1430     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1431
1432     /* Pre-computed circle */
1433
1434     GLfloat *sint,*cost;
1435
1436     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
1437
1438     fghCircleTable(&sint,&cost,-slices,FALSE);
1439
1440     /* Cover the base and top */
1441
1442     glBegin(GL_TRIANGLE_FAN);
1443         glNormal3f(0, 0, -1 );
1444         glVertex3f(0, 0,  0 );
1445         for (j=0; j<=slices; j++)
1446           glVertex3f(cost[j]*radf, sint[j]*radf, 0);
1447     glEnd();
1448
1449     glBegin(GL_TRIANGLE_FAN);
1450         glNormal3f(0, 0,          1     );
1451         glVertex3f(0, 0, (GLfloat)height);
1452         for (j=slices; j>=0; j--)
1453           glVertex3f(cost[j]*radf, sint[j]*radf, (GLfloat)height);
1454     glEnd();
1455
1456     /* Do the stacks */
1457
1458     z0 = 0;
1459     z1 = zStep;
1460
1461     for (i=1; i<=stacks; i++)
1462     {
1463         if (i==stacks)
1464             z1 = (GLfloat)height;
1465
1466         glBegin(GL_TRIANGLE_STRIP);
1467             for (j=0; j<=slices; j++ )
1468             {
1469                 glNormal3f(cost[j],      sint[j],      0  );
1470                 glVertex3f(cost[j]*radf, sint[j]*radf, z0 );
1471                 glVertex3f(cost[j]*radf, sint[j]*radf, z1 );
1472             }
1473         glEnd();
1474
1475         z0 = z1; z1 += zStep;
1476     }
1477
1478     /* Release sin and cos tables */
1479
1480     free(sint);
1481     free(cost);
1482 }
1483
1484 /*
1485  * Draws a wire cylinder
1486  */
1487 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
1488 {
1489     int i,j;
1490
1491     /* Step in z and radius as stacks are drawn. */
1492     GLfloat radf = (GLfloat)radius;
1493           GLfloat z = 0;
1494     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1495
1496     /* Pre-computed circle */
1497
1498     GLfloat *sint,*cost;
1499
1500     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
1501
1502     fghCircleTable(&sint,&cost,-slices,FALSE);
1503
1504     /* Draw the stacks... */
1505
1506     for (i=0; i<=stacks; i++)
1507     {
1508         if (i==stacks)
1509             z = (GLfloat)height;
1510
1511         glBegin(GL_LINE_LOOP);
1512
1513             for( j=0; j<slices; j++ )
1514             {
1515                 glNormal3f(cost[j],      sint[j],      0);
1516                 glVertex3f(cost[j]*radf, sint[j]*radf, z);
1517             }
1518
1519         glEnd();
1520
1521         z += zStep;
1522     }
1523
1524     /* Draw the slices */
1525
1526     glBegin(GL_LINES);
1527
1528         for (j=0; j<slices; j++)
1529         {
1530             glNormal3f(cost[j],      sint[j],               0     );
1531             glVertex3f(cost[j]*radf, sint[j]*radf,          0     );
1532             glVertex3f(cost[j]*radf, sint[j]*radf, (GLfloat)height);
1533         }
1534
1535     glEnd();
1536
1537     /* Release sin and cos tables */
1538
1539     free(sint);
1540     free(cost);
1541 }
1542
1543 /*
1544  * Draws a wire torus
1545  */
1546 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1547 {
1548   GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
1549   GLfloat phi, psi, dpsi, dphi;
1550   GLfloat *vertex, *normal;
1551   int    i, j;
1552   GLfloat spsi, cpsi, sphi, cphi ;
1553
1554   FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
1555
1556   if ( nSides < 1 ) nSides = 1;
1557   if ( nRings < 1 ) nRings = 1;
1558
1559   /* Allocate the vertices array */
1560   vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1561   normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1562
1563   glPushMatrix();
1564
1565   dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings) ;
1566   dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides) ;
1567   psi  = 0.0f;
1568
1569   for( j=0; j<nRings; j++ )
1570   {
1571 #ifdef __cplusplus
1572     cpsi = cosf( psi ) ;
1573     spsi = sinf( psi ) ;
1574 #else
1575     cpsi = (float)cos( (double)psi ) ;
1576     spsi = (float)sin( (double)psi ) ;
1577 #endif  /* __cplusplus */
1578     phi = 0.0f;
1579
1580     for( i=0; i<nSides; i++ )
1581     {
1582       int offset = 3 * ( j * nSides + i ) ;
1583 #ifdef __cplusplus
1584       cphi = cosf( phi ) ;
1585       sphi = sinf( phi ) ;
1586 #else
1587       cphi = (float)cos( (double)phi ) ;
1588       sphi = (float)sin( (double)phi ) ;
1589 #endif  /* __cplusplus */
1590       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
1591       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
1592       *(vertex + offset + 2) =                    sphi * iradius  ;
1593       *(normal + offset + 0) = cpsi * cphi ;
1594       *(normal + offset + 1) = spsi * cphi ;
1595       *(normal + offset + 2) =        sphi ;
1596       phi += dphi;
1597     }
1598
1599     psi += dpsi;
1600   }
1601
1602   for( i=0; i<nSides; i++ )
1603   {
1604     glBegin( GL_LINE_LOOP );
1605
1606     for( j=0; j<nRings; j++ )
1607     {
1608       int offset = 3 * ( j * nSides + i ) ;
1609       glNormal3fv( normal + offset );
1610       glVertex3fv( vertex + offset );
1611     }
1612
1613     glEnd();
1614   }
1615
1616   for( j=0; j<nRings; j++ )
1617   {
1618     glBegin(GL_LINE_LOOP);
1619
1620     for( i=0; i<nSides; i++ )
1621     {
1622       int offset = 3 * ( j * nSides + i ) ;
1623       glNormal3fv( normal + offset );
1624       glVertex3fv( vertex + offset );
1625     }
1626
1627     glEnd();
1628   }
1629
1630   free ( vertex ) ;
1631   free ( normal ) ;
1632   glPopMatrix();
1633 }
1634
1635 /*
1636  * Draws a solid torus
1637  */
1638 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1639 {
1640   GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
1641   GLfloat phi, psi, dpsi, dphi;
1642   GLfloat *vertex, *normal;
1643   int    i, j;
1644   GLfloat spsi, cpsi, sphi, cphi ;
1645
1646   FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
1647
1648   if ( nSides < 1 ) nSides = 1;
1649   if ( nRings < 1 ) nRings = 1;
1650
1651   /* Increment the number of sides and rings to allow for one more point than surface */
1652   nSides ++ ;
1653   nRings ++ ;
1654
1655   /* Allocate the vertices array */
1656   vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1657   normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1658
1659   glPushMatrix();
1660
1661   dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings - 1) ;
1662   dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides - 1) ;
1663   psi  = 0.0f;
1664
1665   for( j=0; j<nRings; j++ )
1666   {
1667 #ifdef __cplusplus
1668     cpsi = cosf( psi ) ;
1669     spsi = sinf( psi ) ;
1670 #else
1671     cpsi = (float)cos( (double)psi ) ;
1672     spsi = (float)sin( (double)psi ) ;
1673 #endif  /* __cplusplus */
1674     phi = 0.0f;
1675
1676     for( i=0; i<nSides; i++ )
1677     {
1678       int offset = 3 * ( j * nSides + i ) ;
1679 #ifdef __cplusplus
1680       cphi = cosf( phi ) ;
1681       sphi = sinf( phi ) ;
1682 #else
1683       cphi = (float)cos( (double)phi ) ;
1684       sphi = (float)sin( (double)phi ) ;
1685 #endif  /* __cplusplus */
1686       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
1687       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
1688       *(vertex + offset + 2) =                    sphi * iradius  ;
1689       *(normal + offset + 0) = cpsi * cphi ;
1690       *(normal + offset + 1) = spsi * cphi ;
1691       *(normal + offset + 2) =        sphi ;
1692       phi += dphi;
1693     }
1694
1695     psi += dpsi;
1696   }
1697
1698     glBegin( GL_QUADS );
1699   for( i=0; i<nSides-1; i++ )
1700   {
1701     for( j=0; j<nRings-1; j++ )
1702     {
1703       int offset = 3 * ( j * nSides + i ) ;
1704       glNormal3fv( normal + offset );
1705       glVertex3fv( vertex + offset );
1706       glNormal3fv( normal + offset + 3 );
1707       glVertex3fv( vertex + offset + 3 );
1708       glNormal3fv( normal + offset + 3 * nSides + 3 );
1709       glVertex3fv( vertex + offset + 3 * nSides + 3 );
1710       glNormal3fv( normal + offset + 3 * nSides );
1711       glVertex3fv( vertex + offset + 3 * nSides );
1712     }
1713   }
1714
1715   glEnd();
1716
1717   free ( vertex ) ;
1718   free ( normal ) ;
1719   glPopMatrix();
1720 }
1721 #endif /* EGL_VERSION_1_0 */
1722
1723
1724
1725 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1726 /* Macro to generate interface functions */
1727 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
1728     void FGAPIENTRY glutWire##nameICaps( void )\
1729     {\
1730         FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
1731         fgh##nameICaps( TRUE );\
1732     }\
1733     void FGAPIENTRY glutSolid##nameICaps( void )\
1734     {\
1735         FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
1736         fgh##nameICaps( FALSE );\
1737     }
1738
1739 void FGAPIENTRY glutWireCube( double dSize )
1740 {
1741     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
1742     fghCube( (GLfloat)dSize, TRUE );
1743 }
1744 void FGAPIENTRY glutSolidCube( double dSize )
1745 {
1746     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
1747     fghCube( (GLfloat)dSize, FALSE );
1748 }
1749
1750 DECLARE_SHAPE_INTERFACE(Dodecahedron)
1751 DECLARE_SHAPE_INTERFACE(Icosahedron)
1752 DECLARE_SHAPE_INTERFACE(Octahedron)
1753 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
1754
1755 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
1756 {
1757     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
1758     fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
1759 }
1760 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
1761 {
1762     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
1763     fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
1764 }
1765
1766 DECLARE_SHAPE_INTERFACE(Tetrahedron)
1767
1768
1769 /*** END OF FILE ***/