converted all tabs to spaces, hate if they are mixed...
[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, vbo_normals;
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, vbo_normals, ibo_elements;
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 /* -- Now the various shapes involving circles -- */
761 /*
762  * Compute lookup table of cos and sin values forming a circle
763  * (or half circle if halfCircle==TRUE)
764  *
765  * Notes:
766  *    It is the responsibility of the caller to free these tables
767  *    The size of the table is (n+1) to form a connected loop
768  *    The last entry is exactly the same as the first
769  *    The sign of n can be flipped to get the reverse loop
770  */
771 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
772 {
773     int i;
774     
775     /* Table size, the sign of n flips the circle direction */
776     const int size = abs(n);
777
778     /* Determine the angle between samples */
779     const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
780
781     /* Allocate memory for n samples, plus duplicate of first entry at the end */
782     *sint = malloc(sizeof(GLfloat) * (size+1));
783     *cost = malloc(sizeof(GLfloat) * (size+1));
784
785     /* Bail out if memory allocation fails, fgError never returns */
786     if (!(*sint) || !(*cost))
787     {
788         free(*sint);
789         free(*cost);
790         fgError("Failed to allocate memory in fghCircleTable");
791     }
792
793     /* Compute cos and sin around the circle */
794     (*sint)[0] = 0.0;
795     (*cost)[0] = 1.0;
796
797     for (i=1; i<size; i++)
798     {
799 #ifdef __cplusplus
800         (*sint)[i] = sinf(angle*i);
801         (*cost)[i] = cosf(angle*i);
802 #else
803         (*sint)[i] = (float)sin((double)(angle*i));
804         (*cost)[i] = (float)cos((double)(angle*i));
805 #endif  /* __cplusplus */
806     }
807
808     
809     if (halfCircle)
810     {
811         (*sint)[size] =  0.0f;  /* sin PI */
812         (*cost)[size] = -1.0f;  /* cos PI */
813     }
814     else
815     {
816         /* Last sample is duplicate of the first (sin or cos of 2 PI) */
817         (*sint)[size] = (*sint)[0];
818         (*cost)[size] = (*cost)[0];
819     }
820 }
821
822 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
823 {
824     int i,j;
825     int idx = 0;    /* idx into vertex/normal buffer */
826     GLfloat x,y,z;
827
828     /* Pre-computed circle */
829     GLfloat *sint1,*cost1;
830     GLfloat *sint2,*cost2;
831
832     /* number of unique vertices */
833     if (slices==0 || stacks<2)
834     {
835         /* nothing to generate */
836         *nVert = 0;
837         return;
838     }
839     *nVert = slices*(stacks-1)+2;
840
841     /* precompute values on unit circle */
842     fghCircleTable(&sint1,&cost1,-slices,FALSE);
843     fghCircleTable(&sint2,&cost2, stacks,TRUE);
844
845     /* Allocate vertex and normal buffers, bail out if memory allocation fails */
846     *vertices = malloc((*nVert)*3*sizeof(GLfloat));
847     *normals  = malloc((*nVert)*3*sizeof(GLfloat));
848     if (!(vertices) || !(normals))
849     {
850         free(*vertices);
851         free(*normals);
852         fgError("Failed to allocate memory in fghGenerateSphere");
853     }
854
855     /* top */
856     (*vertices)[0] = 0.f;
857     (*vertices)[1] = 0.f;
858     (*vertices)[2] = radius;
859     (*normals )[0] = 0.f;
860     (*normals )[1] = 0.f;
861     (*normals )[2] = 1.f;
862     idx = 3;
863
864     /* each stack */
865     for( i=1; i<stacks; i++ )
866     {
867         for(j=0; j<slices; j++, idx+=3)
868         {
869             x = cost1[j]*sint2[i];
870             y = sint1[j]*sint2[i];
871             z = cost2[i];
872
873             (*vertices)[idx  ] = x*radius;
874             (*vertices)[idx+1] = y*radius;
875             (*vertices)[idx+2] = z*radius;
876             (*normals )[idx  ] = x;
877             (*normals )[idx+1] = y;
878             (*normals )[idx+2] = z;
879         }
880     }
881
882     /* bottom */
883     (*vertices)[idx  ] =  0.f;
884     (*vertices)[idx+1] =  0.f;
885     (*vertices)[idx+2] = -radius;
886     (*normals )[idx  ] =  0.f;
887     (*normals )[idx+1] =  0.f;
888     (*normals )[idx+2] = -1.f;
889
890     /* Done creating vertices, release sin and cos tables */
891     free(sint1);
892     free(cost1);
893     free(sint2);
894     free(cost2);
895 }
896
897
898 /* -- INTERNAL DRAWING functions --------------------------------------- */
899 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
900     static void fgh##nameICaps( GLboolean useWireMode )\
901     {\
902         if (!name##Cached)\
903         {\
904             fgh##nameICaps##Generate();\
905             name##Cached = GL_TRUE;\
906         }\
907         \
908         if (useWireMode)\
909         {\
910             fghDrawGeometryWire (name##_verts,name##_norms,\
911                                                              nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE);\
912         }\
913         else\
914         {\
915             fghDrawGeometrySolid(name##_verts,name##_norms,vertIdxs,\
916                                  nameCaps##_VERT_PER_OBJ, nameCaps##_VERT_PER_OBJ_TRI); \
917         }\
918     }
919 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps)                        _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
920 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
921
922 static void fghCube( GLfloat dSize, GLboolean useWireMode )
923 {
924     GLfloat *vertices;
925
926     if (!cubeCached)
927     {
928         fghCubeGenerate();
929         cubeCached = GL_TRUE;
930     }
931
932     if (dSize!=1.f)
933     {
934         /* Need to build new vertex list containing vertices for cube of different size */
935         int i;
936
937         vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
938
939         /* Bail out if memory allocation fails, fgError never returns */
940         if (!vertices)
941         {
942             free(vertices);
943             fgError("Failed to allocate memory in fghCube");
944         }
945
946         for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
947             vertices[i] = dSize*cube_verts[i];
948     }
949     else
950         vertices = cube_verts;
951
952     if (useWireMode)
953         fghDrawGeometryWire (vertices, cube_norms,
954                  CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE);
955     else
956         fghDrawGeometrySolid(vertices, cube_norms, cube_vertIdxs,
957                  CUBE_VERT_PER_OBJ, CUBE_VERT_PER_OBJ_TRI);
958
959     if (dSize!=1.f)
960         /* cleanup allocated memory */
961         free(vertices);
962 }
963
964 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON);
965 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON);
966 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON);
967 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON);
968 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON);
969
970 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
971 {
972     GLfloat *vertices;
973     GLfloat * normals;
974     GLsizei    numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
975     GLsizei    numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
976     GLsizei    numFace = numTetr*TETRAHEDRON_NUM_FACES;
977
978     if (numTetr)
979     {
980         /* Allocate memory */
981         vertices = malloc(numVert*3 * sizeof(GLfloat));
982         normals  = malloc(numVert*3 * sizeof(GLfloat));
983         /* Bail out if memory allocation fails, fgError never returns */
984         if (!vertices || !normals)
985         {
986             free(vertices);
987             free(normals);
988             fgError("Failed to allocate memory in fghSierpinskiSponge");
989         }
990
991         /* Generate elements */
992         fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
993
994         /* Draw and cleanup */
995         if (useWireMode)
996             fghDrawGeometryWire (vertices,normals,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE);
997         else
998             fghDrawGeometrySolid(vertices,normals,NULL,numVert,numVert);
999
1000         free(vertices);
1001         free(normals );
1002     }
1003 }
1004
1005
1006 #ifndef GL_ES_VERSION_2_0
1007 static void fghSphere( double radius, GLint slices, GLint stacks, GLboolean useWireMode )
1008 {
1009     int i,j,idx, nVert;
1010     GLfloat *vertices, *normals;
1011
1012     if (slices * stacks > 65535)
1013     fgWarning("fghSphere: too many slices or stacks requested, indices will wrap");
1014
1015     /* Generate vertices and normals */
1016     fghGenerateSphere((GLfloat)radius,slices,stacks,&vertices,&normals,&nVert);
1017     
1018     if (nVert==0)
1019         /* nothing to draw */
1020         return;
1021
1022     if (useWireMode)
1023     {
1024         GLushort  *sliceIdx, *stackIdx;
1025         /* First, generate vertex index arrays for drawing with glDrawElements
1026          * We have a bunch of line_loops to draw for each stack, and a
1027          * bunch for each slice.
1028          */
1029
1030         sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1031         stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1032
1033         /* generate for each stack */
1034         for (i=0,idx=0; i<slices; i++)
1035         {
1036             GLushort offset = 1+i;                  /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1037             sliceIdx[idx++] = 0;                    /* vertex on top */
1038             for (j=0; j<stacks-1; j++, idx++)
1039             {
1040                 sliceIdx[idx] = offset+j*slices;
1041             }
1042             sliceIdx[idx++] = nVert-1;              /* zero based index, last element in array... */
1043         }
1044
1045         /* generate for each stack */
1046         for (i=0,idx=0; i<stacks-1; i++)
1047         {
1048             GLushort offset = 1+i*slices;           /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1049             for (j=0; j<slices; j++, idx++)
1050             {
1051                 stackIdx[idx] = offset+j;
1052             }
1053         }
1054
1055         /* draw */
1056         glEnableClientState(GL_VERTEX_ARRAY);
1057         glEnableClientState(GL_NORMAL_ARRAY);
1058
1059         glVertexPointer(3, GL_FLOAT, 0, vertices);
1060         glNormalPointer(GL_FLOAT, 0, normals);
1061         /*draw slices*/
1062         for (i=0; i<slices; i++)
1063             glDrawElements(GL_LINE_STRIP,stacks+1,GL_UNSIGNED_SHORT,sliceIdx+i*(stacks+1));
1064         /*draw stacks*/
1065         for (i=0; i<stacks-1; i++)
1066             glDrawElements(GL_LINE_LOOP, slices,GL_UNSIGNED_SHORT,stackIdx+i*slices);
1067
1068         glDisableClientState(GL_VERTEX_ARRAY);
1069         glDisableClientState(GL_NORMAL_ARRAY);
1070
1071         /* cleanup allocated memory */
1072         free(sliceIdx);
1073         free(stackIdx);
1074     }
1075     else
1076     {
1077         GLushort  *topIdx, *bottomIdx, *stripIdx;
1078         /* First, generate vertex index arrays for drawing with glDrawElements
1079          * Top and bottom are covered with a triangle fan
1080          * Each other stack with triangle strip. Only need to generate on
1081          * of those as we'll have to draw each stack separately, and can
1082          * just use different offsets in glDrawElements.
1083          */
1084
1085         /* Allocate buffers for indices, bail out if memory allocation fails */
1086         topIdx = malloc((slices+2)*sizeof(GLushort));
1087         bottomIdx = malloc((slices+2)*sizeof(GLushort));
1088         stripIdx = malloc((slices+1)*2*(stacks-2)*sizeof(GLushort));
1089         if (!(topIdx) || !(bottomIdx) || !(stripIdx))
1090         {
1091             free(topIdx);
1092             free(bottomIdx);
1093             free(stripIdx);
1094             fgError("Failed to allocate memory in fghGenerateSphere");
1095         }
1096
1097         /* TODO: Can do top and bottom as Triangle strip as well
1098            (just need to repeat top/btoom vertex a lot). Then we can draw
1099            the whole thing with just one index array and one for-looped call
1100            to glDrawElements.. That'll make it easier to reuse code with other
1101            Circular objects too
1102            */
1103         topIdx[0]=0;
1104         topIdx[1] = 1;                              /* repeat first slice's idx for closing off shape */
1105         for (j=slices, idx=2; j>0; j--, idx++)
1106             topIdx[idx] = j;
1107
1108         bottomIdx[0]=nVert-1;                       /* zero based index, last element in array... */
1109         for (j=0, idx=1; j<slices; j++, idx++)
1110             bottomIdx[idx] = nVert-(slices+1)+j;
1111         bottomIdx[idx] = nVert-(slices+1);          /* repeat first slice's idx for closing off shape */
1112
1113         /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1114         for (i=0,idx=0; i<stacks-2; i++, idx+=2)
1115         {
1116             GLushort offset = 1+i*slices;             /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1117             for (j=0; j<slices; j++, idx+=2)
1118             {
1119                 stripIdx[idx  ] = offset+j+slices;
1120                 stripIdx[idx+1] = offset+j;
1121             }
1122             stripIdx[idx  ] = offset+slices;        /* repeat first slice's idx for closing off shape */
1123             stripIdx[idx+1] = offset+0;
1124         }
1125
1126
1127         /* draw */
1128         glEnableClientState(GL_VERTEX_ARRAY);
1129         glEnableClientState(GL_NORMAL_ARRAY);
1130
1131         glVertexPointer(3, GL_FLOAT, 0, vertices);
1132         glNormalPointer(GL_FLOAT, 0, normals);
1133         /*draw top*/
1134         glDrawElements(GL_TRIANGLE_FAN,slices+2,GL_UNSIGNED_SHORT,topIdx);
1135         /*draw stacks*/
1136         for (i=0; i<stacks-2; i++)
1137             glDrawElements(GL_TRIANGLE_STRIP,(slices+1)*2,GL_UNSIGNED_SHORT,stripIdx+i*(slices+1)*2);
1138         /*draw bottom*/
1139         glDrawElements(GL_TRIANGLE_FAN,slices+2,GL_UNSIGNED_SHORT,bottomIdx);
1140
1141         glDisableClientState(GL_VERTEX_ARRAY);
1142         glDisableClientState(GL_NORMAL_ARRAY);
1143
1144         /* cleanup allocated memory */
1145         free(topIdx);
1146         free(bottomIdx);
1147         free(stripIdx);
1148     }
1149     
1150     /* cleanup allocated memory */
1151     free(vertices);
1152     free(normals);
1153 }
1154
1155
1156
1157 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
1158
1159
1160 /*
1161  * Draws a solid sphere
1162  */
1163 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
1164 {
1165     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
1166
1167     fghSphere( radius, slices, stacks, FALSE );
1168 }
1169
1170 /*
1171  * Draws a wire sphere
1172  */
1173 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
1174 {
1175     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
1176
1177     fghSphere( radius, slices, stacks, TRUE );
1178     
1179 }
1180 #endif /* GL_ES_VERSION_2_0 */
1181
1182 #ifndef EGL_VERSION_1_0
1183 /*
1184  * Draws a solid cone
1185  */
1186 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
1187 {
1188     int i,j;
1189
1190     /* Step in z and radius as stacks are drawn. */
1191
1192     GLfloat z0,z1;
1193     GLfloat r0,r1;
1194
1195     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1196     const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1197
1198     /* Scaling factors for vertex normals */
1199
1200 #ifdef __cplusplus
1201     const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
1202     const GLfloat sinn = ( (GLfloat)base   / sqrtf( height * height + base * base ));
1203 #else
1204     const GLfloat cosn = ( (GLfloat)height / (GLfloat)sqrt( (double)(height * height + base * base) ));
1205     const GLfloat sinn = ( (GLfloat)base   / (GLfloat)sqrt( (double)(height * height + base * base) ));
1206 #endif  /* __cplusplus */
1207
1208     /* Pre-computed circle */
1209
1210     GLfloat *sint,*cost;
1211
1212     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
1213
1214     fghCircleTable(&sint,&cost,-slices,FALSE);
1215
1216     /* Cover the circular base with a triangle fan... */
1217
1218     z0 = 0;
1219     z1 = zStep;
1220
1221     r0 = (GLfloat)base;
1222     r1 = r0 - rStep;
1223
1224     glBegin(GL_TRIANGLE_FAN);
1225
1226         glNormal3f(0,0,-1);
1227         glVertex3f(0,0, z0 );
1228
1229         for (j=0; j<=slices; j++)
1230             glVertex3f(cost[j]*r0, sint[j]*r0, z0);
1231
1232     glEnd();
1233
1234     /* Cover each stack with a triangle strip */
1235     for( i=0; i<stacks; i++ )
1236     {
1237         glBegin(GL_TRIANGLE_STRIP);
1238
1239             for(j=0; j<=slices; j++)
1240             {
1241                 glNormal3f(cost[j]*cosn, sint[j]*cosn, sinn);
1242                 glVertex3f(cost[j]*r0,   sint[j]*r0,   z0  );
1243                 glVertex3f(cost[j]*r1,   sint[j]*r1,   z1  );
1244             }
1245
1246             z0 = z1; z1 += zStep;
1247             r0 = r1; r1 -= rStep;
1248
1249         glEnd();
1250     }
1251
1252     /* Release sin and cos tables */
1253
1254     free(sint);
1255     free(cost);
1256 }
1257
1258 /*
1259  * Draws a wire cone
1260  */
1261 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
1262 {
1263     int i,j;
1264
1265     /* Step in z and radius as stacks are drawn. */
1266
1267     GLfloat z = 0;
1268     GLfloat r = (GLfloat)base;
1269
1270     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1271     const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1272
1273     /* Scaling factors for vertex normals */
1274
1275 #ifdef __cplusplus
1276     const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
1277     const GLfloat sinn = ( (GLfloat)base   / sqrtf( height * height + base * base ));
1278 #else
1279     const GLfloat cosn = ( (GLfloat)height / (GLfloat)sqrt( (double)(height * height + base * base) ));
1280     const GLfloat sinn = ( (GLfloat)base   / (GLfloat)sqrt( (double)(height * height + base * base) ));
1281 #endif  /* __cplusplus */
1282
1283     /* Pre-computed circle */
1284
1285     GLfloat *sint,*cost;
1286
1287     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
1288
1289     fghCircleTable(&sint,&cost,-slices,FALSE);
1290
1291     /* Draw the stacks... */
1292
1293     for (i=0; i<stacks; i++)
1294     {
1295         glBegin(GL_LINE_LOOP);
1296
1297             for( j=0; j<slices; j++ )
1298             {
1299                 glNormal3f(cost[j]*sinn, sint[j]*sinn, cosn);
1300                 glVertex3f(cost[j]*r,    sint[j]*r,    z   );
1301             }
1302
1303         glEnd();
1304
1305         z += zStep;
1306         r -= rStep;
1307     }
1308
1309     /* Draw the slices */
1310
1311     r = (GLfloat)base;
1312
1313     glBegin(GL_LINES);
1314
1315         for (j=0; j<slices; j++)
1316         {
1317             glNormal3f(cost[j]*sinn, sint[j]*sinn,          cosn  );
1318             glVertex3f(cost[j]*r,    sint[j]*r,             0     );
1319             glVertex3f(0,            0,            (GLfloat)height);
1320         }
1321
1322     glEnd();
1323
1324     /* Release sin and cos tables */
1325
1326     free(sint);
1327     free(cost);
1328 }
1329
1330
1331 /*
1332  * Draws a solid cylinder
1333  */
1334 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
1335 {
1336     int i,j;
1337
1338     /* Step in z and radius as stacks are drawn. */
1339     GLfloat radf = (GLfloat)radius;
1340     GLfloat z0,z1;
1341     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1342
1343     /* Pre-computed circle */
1344
1345     GLfloat *sint,*cost;
1346
1347     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
1348
1349     fghCircleTable(&sint,&cost,-slices,FALSE);
1350
1351     /* Cover the base and top */
1352
1353     glBegin(GL_TRIANGLE_FAN);
1354         glNormal3f(0, 0, -1 );
1355         glVertex3f(0, 0,  0 );
1356         for (j=0; j<=slices; j++)
1357           glVertex3f(cost[j]*radf, sint[j]*radf, 0);
1358     glEnd();
1359
1360     glBegin(GL_TRIANGLE_FAN);
1361         glNormal3f(0, 0,          1     );
1362         glVertex3f(0, 0, (GLfloat)height);
1363         for (j=slices; j>=0; j--)
1364           glVertex3f(cost[j]*radf, sint[j]*radf, (GLfloat)height);
1365     glEnd();
1366
1367     /* Do the stacks */
1368
1369     z0 = 0;
1370     z1 = zStep;
1371
1372     for (i=1; i<=stacks; i++)
1373     {
1374         if (i==stacks)
1375             z1 = (GLfloat)height;
1376
1377         glBegin(GL_TRIANGLE_STRIP);
1378             for (j=0; j<=slices; j++ )
1379             {
1380                 glNormal3f(cost[j],      sint[j],      0  );
1381                 glVertex3f(cost[j]*radf, sint[j]*radf, z0 );
1382                 glVertex3f(cost[j]*radf, sint[j]*radf, z1 );
1383             }
1384         glEnd();
1385
1386         z0 = z1; z1 += zStep;
1387     }
1388
1389     /* Release sin and cos tables */
1390
1391     free(sint);
1392     free(cost);
1393 }
1394
1395 /*
1396  * Draws a wire cylinder
1397  */
1398 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
1399 {
1400     int i,j;
1401
1402     /* Step in z and radius as stacks are drawn. */
1403     GLfloat radf = (GLfloat)radius;
1404           GLfloat z = 0;
1405     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1406
1407     /* Pre-computed circle */
1408
1409     GLfloat *sint,*cost;
1410
1411     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
1412
1413     fghCircleTable(&sint,&cost,-slices,FALSE);
1414
1415     /* Draw the stacks... */
1416
1417     for (i=0; i<=stacks; i++)
1418     {
1419         if (i==stacks)
1420             z = (GLfloat)height;
1421
1422         glBegin(GL_LINE_LOOP);
1423
1424             for( j=0; j<slices; j++ )
1425             {
1426                 glNormal3f(cost[j],      sint[j],      0);
1427                 glVertex3f(cost[j]*radf, sint[j]*radf, z);
1428             }
1429
1430         glEnd();
1431
1432         z += zStep;
1433     }
1434
1435     /* Draw the slices */
1436
1437     glBegin(GL_LINES);
1438
1439         for (j=0; j<slices; j++)
1440         {
1441             glNormal3f(cost[j],      sint[j],               0     );
1442             glVertex3f(cost[j]*radf, sint[j]*radf,          0     );
1443             glVertex3f(cost[j]*radf, sint[j]*radf, (GLfloat)height);
1444         }
1445
1446     glEnd();
1447
1448     /* Release sin and cos tables */
1449
1450     free(sint);
1451     free(cost);
1452 }
1453
1454 /*
1455  * Draws a wire torus
1456  */
1457 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1458 {
1459   GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
1460   GLfloat phi, psi, dpsi, dphi;
1461   GLfloat *vertex, *normal;
1462   int    i, j;
1463   GLfloat spsi, cpsi, sphi, cphi ;
1464
1465   FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
1466
1467   if ( nSides < 1 ) nSides = 1;
1468   if ( nRings < 1 ) nRings = 1;
1469
1470   /* Allocate the vertices array */
1471   vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1472   normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1473
1474   glPushMatrix();
1475
1476   dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings) ;
1477   dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides) ;
1478   psi  = 0.0f;
1479
1480   for( j=0; j<nRings; j++ )
1481   {
1482 #ifdef __cplusplus
1483     cpsi = cosf( psi ) ;
1484     spsi = sinf( psi ) ;
1485 #else
1486     cpsi = (float)cos( (double)psi ) ;
1487     spsi = (float)sin( (double)psi ) ;
1488 #endif  /* __cplusplus */
1489     phi = 0.0f;
1490
1491     for( i=0; i<nSides; i++ )
1492     {
1493       int offset = 3 * ( j * nSides + i ) ;
1494 #ifdef __cplusplus
1495       cphi = cosf( phi ) ;
1496       sphi = sinf( phi ) ;
1497 #else
1498       cphi = (float)cos( (double)phi ) ;
1499       sphi = (float)sin( (double)phi ) ;
1500 #endif  /* __cplusplus */
1501       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
1502       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
1503       *(vertex + offset + 2) =                    sphi * iradius  ;
1504       *(normal + offset + 0) = cpsi * cphi ;
1505       *(normal + offset + 1) = spsi * cphi ;
1506       *(normal + offset + 2) =        sphi ;
1507       phi += dphi;
1508     }
1509
1510     psi += dpsi;
1511   }
1512
1513   for( i=0; i<nSides; i++ )
1514   {
1515     glBegin( GL_LINE_LOOP );
1516
1517     for( j=0; j<nRings; j++ )
1518     {
1519       int offset = 3 * ( j * nSides + i ) ;
1520       glNormal3fv( normal + offset );
1521       glVertex3fv( vertex + offset );
1522     }
1523
1524     glEnd();
1525   }
1526
1527   for( j=0; j<nRings; j++ )
1528   {
1529     glBegin(GL_LINE_LOOP);
1530
1531     for( i=0; i<nSides; i++ )
1532     {
1533       int offset = 3 * ( j * nSides + i ) ;
1534       glNormal3fv( normal + offset );
1535       glVertex3fv( vertex + offset );
1536     }
1537
1538     glEnd();
1539   }
1540
1541   free ( vertex ) ;
1542   free ( normal ) ;
1543   glPopMatrix();
1544 }
1545
1546 /*
1547  * Draws a solid torus
1548  */
1549 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1550 {
1551   GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
1552   GLfloat phi, psi, dpsi, dphi;
1553   GLfloat *vertex, *normal;
1554   int    i, j;
1555   GLfloat spsi, cpsi, sphi, cphi ;
1556
1557   FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
1558
1559   if ( nSides < 1 ) nSides = 1;
1560   if ( nRings < 1 ) nRings = 1;
1561
1562   /* Increment the number of sides and rings to allow for one more point than surface */
1563   nSides ++ ;
1564   nRings ++ ;
1565
1566   /* Allocate the vertices array */
1567   vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1568   normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1569
1570   glPushMatrix();
1571
1572   dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings - 1) ;
1573   dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides - 1) ;
1574   psi  = 0.0f;
1575
1576   for( j=0; j<nRings; j++ )
1577   {
1578 #ifdef __cplusplus
1579     cpsi = cosf( psi ) ;
1580     spsi = sinf( psi ) ;
1581 #else
1582     cpsi = (float)cos( (double)psi ) ;
1583     spsi = (float)sin( (double)psi ) ;
1584 #endif  /* __cplusplus */
1585     phi = 0.0f;
1586
1587     for( i=0; i<nSides; i++ )
1588     {
1589       int offset = 3 * ( j * nSides + i ) ;
1590 #ifdef __cplusplus
1591       cphi = cosf( phi ) ;
1592       sphi = sinf( phi ) ;
1593 #else
1594       cphi = (float)cos( (double)phi ) ;
1595       sphi = (float)sin( (double)phi ) ;
1596 #endif  /* __cplusplus */
1597       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
1598       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
1599       *(vertex + offset + 2) =                    sphi * iradius  ;
1600       *(normal + offset + 0) = cpsi * cphi ;
1601       *(normal + offset + 1) = spsi * cphi ;
1602       *(normal + offset + 2) =        sphi ;
1603       phi += dphi;
1604     }
1605
1606     psi += dpsi;
1607   }
1608
1609     glBegin( GL_QUADS );
1610   for( i=0; i<nSides-1; i++ )
1611   {
1612     for( j=0; j<nRings-1; j++ )
1613     {
1614       int offset = 3 * ( j * nSides + i ) ;
1615       glNormal3fv( normal + offset );
1616       glVertex3fv( vertex + offset );
1617       glNormal3fv( normal + offset + 3 );
1618       glVertex3fv( vertex + offset + 3 );
1619       glNormal3fv( normal + offset + 3 * nSides + 3 );
1620       glVertex3fv( vertex + offset + 3 * nSides + 3 );
1621       glNormal3fv( normal + offset + 3 * nSides );
1622       glVertex3fv( vertex + offset + 3 * nSides );
1623     }
1624   }
1625
1626   glEnd();
1627
1628   free ( vertex ) ;
1629   free ( normal ) ;
1630   glPopMatrix();
1631 }
1632 #endif /* EGL_VERSION_1_0 */
1633
1634
1635
1636 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1637 /* Macro to generate interface functions */
1638 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
1639     void FGAPIENTRY glutWire##nameICaps( void )\
1640     {\
1641         FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
1642         fgh##nameICaps( TRUE );\
1643     }\
1644     void FGAPIENTRY glutSolid##nameICaps( void )\
1645     {\
1646         FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
1647         fgh##nameICaps( FALSE );\
1648     }
1649
1650 void FGAPIENTRY glutWireCube( double dSize )
1651 {
1652     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
1653     fghCube( (GLfloat)dSize, TRUE );
1654 }
1655 void FGAPIENTRY glutSolidCube( double dSize )
1656 {
1657     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
1658     fghCube( (GLfloat)dSize, FALSE );
1659 }
1660
1661 DECLARE_SHAPE_INTERFACE(Dodecahedron);
1662 DECLARE_SHAPE_INTERFACE(Icosahedron);
1663 DECLARE_SHAPE_INTERFACE(Octahedron);
1664 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron);
1665
1666 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
1667 {
1668     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
1669     fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
1670 }
1671 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
1672 {
1673     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
1674     fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
1675 }
1676
1677 DECLARE_SHAPE_INTERFACE(Tetrahedron);
1678
1679
1680 /*** END OF FILE ***/