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