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