ported sphere. Drawing code is still in the sphere function, that and
[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     /* Generate vertices and normals */
827     fghGenerateSphere((GLfloat)radius,slices,stacks,&vertices,&normals,&nVert);
828     
829     if (nVert==0)
830         /* nothing to draw */
831         return;
832
833     if (useWireMode)
834     {
835         GLuint  *sliceIdx, *stackIdx;
836         /* First, generate vertex index arrays for drawing with glDrawElements
837          * We have a bunch of line_loops to draw for each stack, and a
838          * bunch for each slice.
839          */
840
841         sliceIdx = malloc(slices*(stacks+1)*sizeof(GLuint));
842         stackIdx = malloc(slices*(stacks-1)*sizeof(GLuint));
843
844         /* generate for each stack */
845         for (i=0,idx=0; i<slices; i++)
846         {
847             GLuint offset = 1+i;                    /* start at 1 (0 is top vertex), and we advance one slice as we go along */
848             sliceIdx[idx++] = 0;                    /* vertex on top */
849             for (j=0; j<stacks-1; j++, idx++)
850             {
851                 sliceIdx[idx] = offset+j*slices;
852             }
853             sliceIdx[idx++] = nVert-1;              /* zero based index, last element in array... */
854         }
855
856         /* generate for each stack */
857         for (i=0,idx=0; i<stacks-1; i++)
858         {
859             GLuint offset = 1+i*slices;             /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
860             for (j=0; j<slices; j++, idx++)
861             {
862                 stackIdx[idx] = offset+j;
863             }
864         }
865
866         /* draw */
867         glEnableClientState(GL_VERTEX_ARRAY);
868         glEnableClientState(GL_NORMAL_ARRAY);
869
870         glVertexPointer(3, GL_FLOAT, 0, vertices);
871         glNormalPointer(GL_FLOAT, 0, normals);
872         /*draw slices*/
873         for (i=0; i<slices; i++)
874             glDrawElements(GL_LINE_STRIP,stacks+1,GL_UNSIGNED_INT,sliceIdx+i*(stacks+1));
875         /*draw stacks*/
876         for (i=0; i<stacks-1; i++)
877             glDrawElements(GL_LINE_LOOP, slices,GL_UNSIGNED_INT,stackIdx+i*slices);
878
879         glDisableClientState(GL_VERTEX_ARRAY);
880         glDisableClientState(GL_NORMAL_ARRAY);
881
882         /* cleanup allocated memory */
883         free(sliceIdx);
884         free(stackIdx);
885     }
886     else
887     {
888         GLuint  *topIdx, *bottomIdx, *stripIdx;
889         /* First, generate vertex index arrays for drawing with glDrawElements
890          * Top and bottom are covered with a triangle fan
891          * Each other stack with triangle strip. Only need to generate on
892          * of those as we'll have to draw each stack separately, and can
893          * just use different offsets in glDrawElements.
894          */
895
896         /* Allocate buffers for indices, bail out if memory allocation fails */
897         topIdx = malloc((slices+2)*sizeof(GLuint));
898         bottomIdx = malloc((slices+2)*sizeof(GLuint));
899         stripIdx = malloc((slices+1)*2*(stacks-2)*sizeof(GLuint));
900         if (!(topIdx) || !(bottomIdx) || !(stripIdx))
901         {
902             free(topIdx);
903             free(bottomIdx);
904             free(stripIdx);
905             fgError("Failed to allocate memory in fghGenerateSphere");
906         }
907
908         topIdx[0]=0;
909         topIdx[1] = 1;                              /* repeat first slice's idx for closing off shape */
910         for (j=slices, idx=2; j>0; j--, idx++)
911             topIdx[idx] = j;
912
913         bottomIdx[0]=nVert-1;                       /* zero based index, last element in array... */
914         for (j=0, idx=1; j<slices; j++, idx++)
915             bottomIdx[idx] = nVert-(slices+1)+j;
916         bottomIdx[idx] = nVert-(slices+1);          /* repeat first slice's idx for closing off shape */
917
918         /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
919         for (i=0,idx=0; i<stacks-2; i++, idx+=2)
920         {
921             GLuint offset = 1+i*slices;             /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
922             for (j=0; j<slices; j++, idx+=2)
923             {
924                 stripIdx[idx  ] = offset+j+slices;
925                 stripIdx[idx+1] = offset+j;
926             }
927             stripIdx[idx  ] = offset+slices;        /* repeat first slice's idx for closing off shape */
928             stripIdx[idx+1] = offset+0;
929         }
930
931
932         /* draw */
933         glEnableClientState(GL_VERTEX_ARRAY);
934         glEnableClientState(GL_NORMAL_ARRAY);
935
936         glVertexPointer(3, GL_FLOAT, 0, vertices);
937         glNormalPointer(GL_FLOAT, 0, normals);
938         /*draw top*/
939         glDrawElements(GL_TRIANGLE_FAN,slices+2,GL_UNSIGNED_INT,topIdx);
940         /*draw stacks*/
941         for (i=0; i<stacks-2; i++)
942             glDrawElements(GL_TRIANGLE_STRIP,(slices+1)*2,GL_UNSIGNED_INT,stripIdx+i*(slices+1)*2);
943         /*draw bottom*/
944         glDrawElements(GL_TRIANGLE_FAN,slices+2,GL_UNSIGNED_INT,bottomIdx);
945
946         glDisableClientState(GL_VERTEX_ARRAY);
947         glDisableClientState(GL_NORMAL_ARRAY);
948
949         /* cleanup allocated memory */
950         free(topIdx);
951         free(bottomIdx);
952         free(stripIdx);
953     }
954     
955     /* cleanup allocated memory */
956     free(vertices);
957     free(normals);
958 }
959
960 #endif /* GL_ES_VERSION_2_0 */
961
962
963 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
964
965
966 #ifndef EGL_VERSION_1_0
967 /*
968  * Draws a solid sphere
969  */
970 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
971 {
972     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
973
974     fghSphere( radius, slices, stacks, FALSE );
975 }
976
977 /*
978  * Draws a wire sphere
979  */
980 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
981 {
982     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
983
984     fghSphere( radius, slices, stacks, TRUE );
985     
986 }
987
988 /*
989  * Draws a solid cone
990  */
991 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
992 {
993     int i,j;
994
995     /* Step in z and radius as stacks are drawn. */
996
997     GLfloat z0,z1;
998     GLfloat r0,r1;
999
1000     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1001     const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1002
1003     /* Scaling factors for vertex normals */
1004
1005     const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
1006     const GLfloat sinn = ( (GLfloat)base   / sqrtf( height * height + base * base ));
1007
1008     /* Pre-computed circle */
1009
1010     GLfloat *sint,*cost;
1011
1012     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
1013
1014     fghCircleTable(&sint,&cost,-slices,FALSE);
1015
1016     /* Cover the circular base with a triangle fan... */
1017
1018     z0 = 0;
1019     z1 = zStep;
1020
1021     r0 = (GLfloat)base;
1022     r1 = r0 - rStep;
1023
1024     glBegin(GL_TRIANGLE_FAN);
1025
1026         glNormal3f(0,0,-1);
1027         glVertex3f(0,0, z0 );
1028
1029         for (j=0; j<=slices; j++)
1030             glVertex3f(cost[j]*r0, sint[j]*r0, z0);
1031
1032     glEnd();
1033
1034     /* Cover each stack with a quad strip, except the top stack */
1035
1036     for( i=0; i<stacks-1; i++ )
1037     {
1038         glBegin(GL_QUAD_STRIP);
1039
1040             for(j=0; j<=slices; j++)
1041             {
1042                 glNormal3f(cost[j]*cosn, sint[j]*cosn, sinn);
1043                 glVertex3f(cost[j]*r0,   sint[j]*r0,   z0  );
1044                 glVertex3f(cost[j]*r1,   sint[j]*r1,   z1  );
1045             }
1046
1047             z0 = z1; z1 += zStep;
1048             r0 = r1; r1 -= rStep;
1049
1050         glEnd();
1051     }
1052
1053     /* The top stack is covered with individual triangles */
1054
1055     glBegin(GL_TRIANGLES);
1056
1057         glNormal3f(cost[0]*sinn, sint[0]*sinn, cosn);
1058
1059         for (j=0; j<slices; j++)
1060         {
1061             glVertex3f(cost[j+0]*r0,   sint[j+0]*r0,            z0    );
1062             glVertex3f(0,              0,              (GLfloat)height);
1063             glNormal3f(cost[j+1]*sinn, sint[j+1]*sinn,          cosn  );
1064             glVertex3f(cost[j+1]*r0,   sint[j+1]*r0,            z0    );
1065         }
1066
1067     glEnd();
1068
1069     /* Release sin and cos tables */
1070
1071     free(sint);
1072     free(cost);
1073 }
1074
1075 /*
1076  * Draws a wire cone
1077  */
1078 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
1079 {
1080     int i,j;
1081
1082     /* Step in z and radius as stacks are drawn. */
1083
1084     GLfloat z = 0;
1085     GLfloat r = (GLfloat)base;
1086
1087     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1088     const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1089
1090     /* Scaling factors for vertex normals */
1091
1092     const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
1093     const GLfloat sinn = ( (GLfloat)base   / sqrtf( height * height + base * base ));
1094
1095     /* Pre-computed circle */
1096
1097     GLfloat *sint,*cost;
1098
1099     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
1100
1101     fghCircleTable(&sint,&cost,-slices,FALSE);
1102
1103     /* Draw the stacks... */
1104
1105     for (i=0; i<stacks; i++)
1106     {
1107         glBegin(GL_LINE_LOOP);
1108
1109             for( j=0; j<slices; j++ )
1110             {
1111                 glNormal3f(cost[j]*sinn, sint[j]*sinn, cosn);
1112                 glVertex3f(cost[j]*r,    sint[j]*r,    z   );
1113             }
1114
1115         glEnd();
1116
1117         z += zStep;
1118         r -= rStep;
1119     }
1120
1121     /* Draw the slices */
1122
1123     r = (GLfloat)base;
1124
1125     glBegin(GL_LINES);
1126
1127         for (j=0; j<slices; j++)
1128         {
1129             glNormal3f(cost[j]*sinn, sint[j]*sinn,          cosn  );
1130             glVertex3f(cost[j]*r,    sint[j]*r,             0     );
1131             glVertex3f(0,            0,            (GLfloat)height);
1132         }
1133
1134     glEnd();
1135
1136     /* Release sin and cos tables */
1137
1138     free(sint);
1139     free(cost);
1140 }
1141
1142
1143 /*
1144  * Draws a solid cylinder
1145  */
1146 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
1147 {
1148     int i,j;
1149
1150     /* Step in z and radius as stacks are drawn. */
1151     GLfloat radf = (GLfloat)radius;
1152     GLfloat z0,z1;
1153     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1154
1155     /* Pre-computed circle */
1156
1157     GLfloat *sint,*cost;
1158
1159     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
1160
1161     fghCircleTable(&sint,&cost,-slices,FALSE);
1162
1163     /* Cover the base and top */
1164
1165     glBegin(GL_TRIANGLE_FAN);
1166         glNormal3f(0, 0, -1 );
1167         glVertex3f(0, 0,  0 );
1168         for (j=0; j<=slices; j++)
1169           glVertex3f(cost[j]*radf, sint[j]*radf, 0);
1170     glEnd();
1171
1172     glBegin(GL_TRIANGLE_FAN);
1173         glNormal3f(0, 0,          1     );
1174         glVertex3f(0, 0, (GLfloat)height);
1175         for (j=slices; j>=0; j--)
1176           glVertex3f(cost[j]*radf, sint[j]*radf, (GLfloat)height);
1177     glEnd();
1178
1179     /* Do the stacks */
1180
1181     z0 = 0;
1182     z1 = zStep;
1183
1184     for (i=1; i<=stacks; i++)
1185     {
1186         if (i==stacks)
1187             z1 = (GLfloat)height;
1188
1189         glBegin(GL_QUAD_STRIP);
1190             for (j=0; j<=slices; j++ )
1191             {
1192                 glNormal3f(cost[j],      sint[j],      0  );
1193                 glVertex3f(cost[j]*radf, sint[j]*radf, z0 );
1194                 glVertex3f(cost[j]*radf, sint[j]*radf, z1 );
1195             }
1196         glEnd();
1197
1198         z0 = z1; z1 += zStep;
1199     }
1200
1201     /* Release sin and cos tables */
1202
1203     free(sint);
1204     free(cost);
1205 }
1206
1207 /*
1208  * Draws a wire cylinder
1209  */
1210 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
1211 {
1212     int i,j;
1213
1214     /* Step in z and radius as stacks are drawn. */
1215     GLfloat radf = (GLfloat)radius;
1216           GLfloat z = 0;
1217     const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1218
1219     /* Pre-computed circle */
1220
1221     GLfloat *sint,*cost;
1222
1223     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
1224
1225     fghCircleTable(&sint,&cost,-slices,FALSE);
1226
1227     /* Draw the stacks... */
1228
1229     for (i=0; i<=stacks; i++)
1230     {
1231         if (i==stacks)
1232             z = (GLfloat)height;
1233
1234         glBegin(GL_LINE_LOOP);
1235
1236             for( j=0; j<slices; j++ )
1237             {
1238                 glNormal3f(cost[j],      sint[j],      0);
1239                 glVertex3f(cost[j]*radf, sint[j]*radf, z);
1240             }
1241
1242         glEnd();
1243
1244         z += zStep;
1245     }
1246
1247     /* Draw the slices */
1248
1249     glBegin(GL_LINES);
1250
1251         for (j=0; j<slices; j++)
1252         {
1253             glNormal3f(cost[j],      sint[j],               0     );
1254             glVertex3f(cost[j]*radf, sint[j]*radf,          0     );
1255             glVertex3f(cost[j]*radf, sint[j]*radf, (GLfloat)height);
1256         }
1257
1258     glEnd();
1259
1260     /* Release sin and cos tables */
1261
1262     free(sint);
1263     free(cost);
1264 }
1265
1266 /*
1267  * Draws a wire torus
1268  */
1269 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1270 {
1271   GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
1272   GLfloat phi, psi, dpsi, dphi;
1273   GLfloat *vertex, *normal;
1274   int    i, j;
1275   GLfloat spsi, cpsi, sphi, cphi ;
1276
1277   FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
1278
1279   if ( nSides < 1 ) nSides = 1;
1280   if ( nRings < 1 ) nRings = 1;
1281
1282   /* Allocate the vertices array */
1283   vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1284   normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1285
1286   glPushMatrix();
1287
1288   dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings) ;
1289   dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides) ;
1290   psi  = 0.0f;
1291
1292   for( j=0; j<nRings; j++ )
1293   {
1294     cpsi = cosf( psi ) ;
1295     spsi = sinf( psi ) ;
1296     phi = 0.0f;
1297
1298     for( i=0; i<nSides; i++ )
1299     {
1300       int offset = 3 * ( j * nSides + i ) ;
1301       cphi = cosf( phi ) ;
1302       sphi = sinf( phi ) ;
1303       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
1304       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
1305       *(vertex + offset + 2) =                    sphi * iradius  ;
1306       *(normal + offset + 0) = cpsi * cphi ;
1307       *(normal + offset + 1) = spsi * cphi ;
1308       *(normal + offset + 2) =        sphi ;
1309       phi += dphi;
1310     }
1311
1312     psi += dpsi;
1313   }
1314
1315   for( i=0; i<nSides; i++ )
1316   {
1317     glBegin( GL_LINE_LOOP );
1318
1319     for( j=0; j<nRings; j++ )
1320     {
1321       int offset = 3 * ( j * nSides + i ) ;
1322       glNormal3fv( normal + offset );
1323       glVertex3fv( vertex + offset );
1324     }
1325
1326     glEnd();
1327   }
1328
1329   for( j=0; j<nRings; j++ )
1330   {
1331     glBegin(GL_LINE_LOOP);
1332
1333     for( i=0; i<nSides; i++ )
1334     {
1335       int offset = 3 * ( j * nSides + i ) ;
1336       glNormal3fv( normal + offset );
1337       glVertex3fv( vertex + offset );
1338     }
1339
1340     glEnd();
1341   }
1342
1343   free ( vertex ) ;
1344   free ( normal ) ;
1345   glPopMatrix();
1346 }
1347
1348 /*
1349  * Draws a solid torus
1350  */
1351 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1352 {
1353   GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
1354   GLfloat phi, psi, dpsi, dphi;
1355   GLfloat *vertex, *normal;
1356   int    i, j;
1357   GLfloat spsi, cpsi, sphi, cphi ;
1358
1359   FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
1360
1361   if ( nSides < 1 ) nSides = 1;
1362   if ( nRings < 1 ) nRings = 1;
1363
1364   /* Increment the number of sides and rings to allow for one more point than surface */
1365   nSides ++ ;
1366   nRings ++ ;
1367
1368   /* Allocate the vertices array */
1369   vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1370   normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
1371
1372   glPushMatrix();
1373
1374   dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings - 1) ;
1375   dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides - 1) ;
1376   psi  = 0.0f;
1377
1378   for( j=0; j<nRings; j++ )
1379   {
1380     cpsi = cosf( psi ) ;
1381     spsi = sinf( psi ) ;
1382     phi = 0.0f;
1383
1384     for( i=0; i<nSides; i++ )
1385     {
1386       int offset = 3 * ( j * nSides + i ) ;
1387       cphi = cosf( phi ) ;
1388       sphi = sinf( phi ) ;
1389       *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
1390       *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
1391       *(vertex + offset + 2) =                    sphi * iradius  ;
1392       *(normal + offset + 0) = cpsi * cphi ;
1393       *(normal + offset + 1) = spsi * cphi ;
1394       *(normal + offset + 2) =        sphi ;
1395       phi += dphi;
1396     }
1397
1398     psi += dpsi;
1399   }
1400
1401     glBegin( GL_QUADS );
1402   for( i=0; i<nSides-1; i++ )
1403   {
1404     for( j=0; j<nRings-1; j++ )
1405     {
1406       int offset = 3 * ( j * nSides + i ) ;
1407       glNormal3fv( normal + offset );
1408       glVertex3fv( vertex + offset );
1409       glNormal3fv( normal + offset + 3 );
1410       glVertex3fv( vertex + offset + 3 );
1411       glNormal3fv( normal + offset + 3 * nSides + 3 );
1412       glVertex3fv( vertex + offset + 3 * nSides + 3 );
1413       glNormal3fv( normal + offset + 3 * nSides );
1414       glVertex3fv( vertex + offset + 3 * nSides );
1415     }
1416   }
1417
1418   glEnd();
1419
1420   free ( vertex ) ;
1421   free ( normal ) ;
1422   glPopMatrix();
1423 }
1424 #endif /* EGL_VERSION_1_0 */
1425
1426
1427
1428 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1429 /* Macro to generate interface functions */
1430 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
1431     void FGAPIENTRY glutWire##nameICaps( void )\
1432     {\
1433         FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
1434         fgh##nameICaps( TRUE );\
1435     }\
1436     void FGAPIENTRY glutSolid##nameICaps( void )\
1437     {\
1438         FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
1439         fgh##nameICaps( FALSE );\
1440     }
1441
1442 void FGAPIENTRY glutWireCube( double dSize )
1443 {
1444     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
1445     fghCube( (GLfloat)dSize, TRUE );
1446 }
1447 void FGAPIENTRY glutSolidCube( double dSize )
1448 {
1449     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
1450     fghCube( (GLfloat)dSize, FALSE );
1451 }
1452
1453 DECLARE_SHAPE_INTERFACE(Dodecahedron);
1454 DECLARE_SHAPE_INTERFACE(Icosahedron);
1455 DECLARE_SHAPE_INTERFACE(Octahedron);
1456 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron);
1457
1458 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
1459 {
1460     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
1461     fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
1462 }
1463 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
1464 {
1465     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
1466     fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
1467 }
1468
1469 DECLARE_SHAPE_INTERFACE(Tetrahedron);
1470
1471
1472 /*** END OF FILE ***/