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