4 * Freeglut geometry rendering methods.
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
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:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
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.
28 #include <GL/freeglut.h>
29 #include "fg_internal.h"
33 /* declare for drawing using the different OpenGL versions here so we can
34 have a nice code order below */
35 #ifndef GL_ES_VERSION_2_0
36 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
37 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
38 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
40 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
41 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
43 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
44 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
45 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
46 GLint attribute_v_coord, GLint attribute_v_normal
48 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
49 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
50 GLint attribute_v_coord, GLint attribute_v_normal);
53 * Explanation of the functions has to be separate for the polyhedra and
54 * the non-polyhedra (objects with a circular cross-section).
56 * - We have only implemented the five platonic solids and the rhomboid
57 * dodecahedron. If you need more types of polyhedra, please see
59 * - Solids are drawn by glDrawArrays if composed of triangular faces
60 * (the tetrahedron, octahedron, and icosahedron), or are first
61 * decomposed into triangles and then drawn by glDrawElements if its
62 * faces are squares or pentagons (cube, dodecahedron and rhombic
63 * dodecahedron) as some vertices are repeated in that case.
64 * - WireFrame drawing is done using a GL_LINE_LOOP per face, and thus
65 * issuing one draw call per face. glDrawArrays is always used as no
66 * triangle decomposition is needed to draw faces. We use the "first"
67 * parameter in glDrawArrays to go from face to face.
70 * - We have implemented the sphere, cylinder, cone and torus.
71 * - All shapes are characterized by two parameters: the number of
72 * subdivisions along two axes used to construct the shape's vertices
73 * (e.g. stacks and slices for the sphere).
74 * As different subdivisions are most suitable for different shapes,
75 * and are thus also named differently, I wont provide general comments
77 * - Solids are drawn using glDrawArrays and GL_TRIANGLE_STRIP. Each
78 * strip covers one revolution around one of the two subdivision axes
80 * - WireFrame drawing is done for the subdivisions along the two axes
81 * separately, usually using GL_LINE_LOOP. Vertex index arrays are
82 * built containing the vertices to be drawn for each loop, which are
83 * then drawn using multiple calls to glDrawElements. As the number of
84 * subdivisions along the two axes is not guaranteed to be equal, the
85 * vertex indices for e.g. stacks and slices are stored in separate
86 * arrays, which makes the input to the drawing function a bit clunky,
87 * but allows for the same drawing function to be used for all shapes.
92 * Draw geometric shape in wire mode (only edges)
95 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
96 * The vertex coordinate and normal buffers, and the number of entries in
99 * a vertex indices buffer, optional (never passed for the polyhedra)
100 * GLsizei numParts, GLsizei numVertPerPart
101 * polyhedra: number of faces, and the number of vertices for drawing
103 * non-polyhedra: number of edges to draw for first subdivision (not
104 * necessarily equal to number of subdivisions requested by user, e.g.
105 * as each subdivision is enclosed by two edges), and number of
106 * vertices for drawing each
107 * numParts * numVertPerPart gives the number of entries in the vertex
110 * vertex drawing mode (e.g. always GL_LINE_LOOP for polyhedra, varies
112 * GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
113 * non-polyhedra only: same as the above, but now for subdivisions along
114 * the other axis. Always drawn as GL_LINE_LOOP.
116 * Feel free to contribute better naming ;)
118 static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
119 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
120 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
123 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
124 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
126 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
127 /* User requested a 2.0 draw */
128 fghDrawGeometryWire20(vertices, normals, numVertices,
129 vertIdxs, numParts, numVertPerPart, vertexMode,
130 vertIdxs2, numParts2, numVertPerPart2,
131 attribute_v_coord, attribute_v_normal);
132 #ifndef GL_ES_VERSION_2_0
134 fghDrawGeometryWire11(vertices, normals,
135 vertIdxs, numParts, numVertPerPart, vertexMode,
136 vertIdxs2, numParts2, numVertPerPart2);
140 /* Draw the geometric shape with filled triangles
143 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
144 * The vertex coordinate and normal buffers, and the number of entries in
147 * a vertex indices buffer, optional (not passed for the polyhedra with
149 * GLsizei numParts, GLsizei numVertPerPart
150 * polyhedra: not used for polyhedra with triangular faces
151 (numEdgePerFace==3), as each vertex+normal pair is drawn only once,
152 so no vertex indices are used.
153 Else, the shape was triangulated (DECOMPOSE_TO_TRIANGLE), leading to
154 reuse of some vertex+normal pairs, and thus the need to draw with
155 glDrawElements. numParts is always 1 in this case (we can draw the
156 whole object with one call to glDrawElements as the vertex index
157 array contains separate triangles), and numVertPerPart indicates
158 the number of vertex indices in the vertex array.
159 * non-polyhedra: number of parts (GL_TRIANGLE_STRIPs) to be drawn
160 separately (numParts calls to glDrawElements) to create the object.
161 numVertPerPart indicates the number of vertex indices to be
162 processed at each draw call.
163 * numParts * numVertPerPart gives the number of entries in the vertex
166 static void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
167 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
169 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
170 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
172 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
173 /* User requested a 2.0 draw */
174 fghDrawGeometrySolid20(vertices, normals, numVertices,
175 vertIdxs, numParts, numVertIdxsPerPart,
176 attribute_v_coord, attribute_v_normal);
177 #ifndef GL_ES_VERSION_2_0
179 fghDrawGeometrySolid11(vertices, normals, numVertices,
180 vertIdxs, numParts, numVertIdxsPerPart);
186 /* Version for OpenGL (ES) 1.1 */
187 #ifndef GL_ES_VERSION_2_0
188 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
189 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
190 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
195 glEnableClientState(GL_VERTEX_ARRAY);
196 glEnableClientState(GL_NORMAL_ARRAY);
198 glVertexPointer(3, GL_FLOAT, 0, vertices);
199 glNormalPointer(GL_FLOAT, 0, normals);
203 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
204 for (i=0; i<numParts; i++)
205 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
207 for (i=0; i<numParts; i++)
208 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
211 for (i=0; i<numParts2; i++)
212 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
214 glDisableClientState(GL_VERTEX_ARRAY);
215 glDisableClientState(GL_NORMAL_ARRAY);
219 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
220 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
224 glEnableClientState(GL_VERTEX_ARRAY);
225 glEnableClientState(GL_NORMAL_ARRAY);
227 glVertexPointer(3, GL_FLOAT, 0, vertices);
228 glNormalPointer(GL_FLOAT, 0, normals);
231 glDrawArrays(GL_TRIANGLES, 0, numVertices);
234 for (i=0; i<numParts; i++)
235 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
237 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
239 glDisableClientState(GL_VERTEX_ARRAY);
240 glDisableClientState(GL_NORMAL_ARRAY);
244 /* Version for OpenGL (ES) >= 2.0 */
245 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
246 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
247 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
248 GLint attribute_v_coord, GLint attribute_v_normal
251 GLuint vbo_coords = 0, vbo_normals = 0,
252 ibo_elements = 0, ibo_elements2 = 0;
253 GLsizei numVertIdxs = numParts * numVertPerPart;
254 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
257 if (numVertices > 0 && attribute_v_coord != -1) {
258 fghGenBuffers(1, &vbo_coords);
259 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
260 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
261 vertices, FGH_STATIC_DRAW);
264 if (numVertices > 0 && attribute_v_normal != -1) {
265 fghGenBuffers(1, &vbo_normals);
266 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
267 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
268 normals, FGH_STATIC_DRAW);
271 if (vertIdxs != NULL) {
272 fghGenBuffers(1, &ibo_elements);
273 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
274 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
275 vertIdxs, FGH_STATIC_DRAW);
276 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
279 if (vertIdxs2 != NULL) {
280 fghGenBuffers(1, &ibo_elements2);
281 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
282 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
283 vertIdxs2, FGH_STATIC_DRAW);
284 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
288 fghEnableVertexAttribArray(attribute_v_coord);
289 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
290 fghVertexAttribPointer(
291 attribute_v_coord, /* attribute */
292 3, /* number of elements per vertex, here (x,y,z) */
293 GL_FLOAT, /* the type of each element */
294 GL_FALSE, /* take our values as-is */
295 0, /* no extra data between each position */
296 0 /* offset of first element */
298 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
302 fghEnableVertexAttribArray(attribute_v_normal);
303 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
304 fghVertexAttribPointer(
305 attribute_v_normal, /* attribute */
306 3, /* number of elements per vertex, here (x,y,z) */
307 GL_FLOAT, /* the type of each element */
308 GL_FALSE, /* take our values as-is */
309 0, /* no extra data between each position */
310 0 /* offset of first element */
312 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
316 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
317 for (i=0; i<numParts; i++)
318 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
320 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
321 for (i=0; i<numParts; i++)
322 glDrawElements(vertexMode, numVertPerPart,
323 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
324 /* Clean existing bindings before clean-up */
325 /* Android showed instability otherwise */
326 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
330 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
331 for (i=0; i<numParts2; i++)
332 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
333 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
334 /* Clean existing bindings before clean-up */
335 /* Android showed instability otherwise */
336 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
340 fghDisableVertexAttribArray(attribute_v_coord);
341 if (vbo_normals != 0)
342 fghDisableVertexAttribArray(attribute_v_normal);
345 fghDeleteBuffers(1, &vbo_coords);
346 if (vbo_normals != 0)
347 fghDeleteBuffers(1, &vbo_normals);
348 if (ibo_elements != 0)
349 fghDeleteBuffers(1, &ibo_elements);
350 if (ibo_elements2 != 0)
351 fghDeleteBuffers(1, &ibo_elements2);
357 /* Version for OpenGL (ES) >= 2.0 */
358 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
359 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
360 GLint attribute_v_coord, GLint attribute_v_normal)
362 GLuint vbo_coords = 0, vbo_normals = 0, ibo_elements = 0;
363 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
366 if (numVertices > 0 && attribute_v_coord != -1) {
367 fghGenBuffers(1, &vbo_coords);
368 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
369 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
370 vertices, FGH_STATIC_DRAW);
371 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
374 if (numVertices > 0 && attribute_v_normal != -1) {
375 fghGenBuffers(1, &vbo_normals);
376 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
377 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
378 normals, FGH_STATIC_DRAW);
379 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
382 if (vertIdxs != NULL) {
383 fghGenBuffers(1, &ibo_elements);
384 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
385 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
386 vertIdxs, FGH_STATIC_DRAW);
387 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
391 fghEnableVertexAttribArray(attribute_v_coord);
392 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
393 fghVertexAttribPointer(
394 attribute_v_coord, /* attribute */
395 3, /* number of elements per vertex, here (x,y,z) */
396 GL_FLOAT, /* the type of each element */
397 GL_FALSE, /* take our values as-is */
398 0, /* no extra data between each position */
399 0 /* offset of first element */
401 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
405 fghEnableVertexAttribArray(attribute_v_normal);
406 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
407 fghVertexAttribPointer(
408 attribute_v_normal, /* attribute */
409 3, /* number of elements per vertex, here (x,y,z) */
410 GL_FLOAT, /* the type of each element */
411 GL_FALSE, /* take our values as-is */
412 0, /* no extra data between each position */
413 0 /* offset of first element */
415 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
418 if (vertIdxs == NULL) {
419 glDrawArrays(GL_TRIANGLES, 0, numVertices);
421 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
423 for (i=0; i<numParts; i++) {
424 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
427 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
429 /* Clean existing bindings before clean-up */
430 /* Android showed instability otherwise */
431 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
435 fghDisableVertexAttribArray(attribute_v_coord);
436 if (vbo_normals != 0)
437 fghDisableVertexAttribArray(attribute_v_normal);
440 fghDeleteBuffers(1, &vbo_coords);
441 if (vbo_normals != 0)
442 fghDeleteBuffers(1, &vbo_normals);
443 if (ibo_elements != 0)
444 fghDeleteBuffers(1, &ibo_elements);
450 * Generate all combinations of vertices and normals needed to draw object.
451 * Optional shape decomposition to triangles:
452 * We'll use glDrawElements to draw all shapes that are not naturally
453 * composed of triangles, so generate an index vector here, using the
454 * below sampling scheme.
455 * Be careful to keep winding of all triangles counter-clockwise,
456 * assuming that input has correct winding...
458 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
459 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
461 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
463 int i,j,numEdgeIdxPerFace;
464 GLubyte *vertSamps = NULL;
465 switch (numEdgePerFace)
468 /* nothing to do here, we'll draw with glDrawArrays */
471 vertSamps = vert4Decomp;
472 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
475 vertSamps = vert5Decomp;
476 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
480 * Build array with vertices using vertex coordinates and vertex indices
481 * Do same for normals.
482 * Need to do this because of different normals at shared vertices.
484 for (i=0; i<numFaces; i++)
487 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
488 for (j=0; j<numEdgePerFace; j++)
490 int outIdx = i*numEdgePerFace*3+j*3;
491 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
493 vertOut[outIdx ] = vertices[vertIdx ];
494 vertOut[outIdx+1] = vertices[vertIdx+1];
495 vertOut[outIdx+2] = vertices[vertIdx+2];
497 normOut[outIdx ] = normals [normIdx ];
498 normOut[outIdx+1] = normals [normIdx+1];
499 normOut[outIdx+2] = normals [normIdx+2];
502 /* generate vertex indices for each face */
504 for (j=0; j<numEdgeIdxPerFace; j++)
505 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
509 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
511 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
512 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
516 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
517 /* -- stuff that can be cached -- */
518 /* Cache of input to glDrawArrays or glDrawElements
519 * In general, we build arrays with all vertices or normals.
520 * We cant compress this and use glDrawElements as all combinations of
521 * vertices and normals are unique.
523 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
524 static GLboolean name##Cached = FALSE;\
525 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
526 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
527 static void fgh##nameICaps##Generate()\
529 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
530 name##_v, name##_vi, name##_n,\
531 name##_verts, name##_norms);\
533 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
534 static GLboolean name##Cached = FALSE;\
535 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
536 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
537 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
538 static void fgh##nameICaps##Generate()\
540 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
541 name##_v, name##_vi, name##_n,\
542 name##_verts, name##_norms, name##_vertIdxs);\
546 #define CUBE_NUM_VERT 8
547 #define CUBE_NUM_FACES 6
548 #define CUBE_NUM_EDGE_PER_FACE 4
549 #define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
550 #define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
551 #define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
552 /* Vertex Coordinates */
553 static GLfloat cube_v[CUBE_NUM_VERT*3] =
565 static GLfloat cube_n[CUBE_NUM_FACES*3] =
575 /* Vertex indices, as quads, before triangulation */
576 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
585 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
587 /* -- Dodecahedron -- */
588 /* Magic Numbers: It is possible to create a dodecahedron by attaching two
589 * pentagons to each face of of a cube. The coordinates of the points are:
590 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
591 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
592 * x = 0.61803398875 and z = 1.61803398875.
594 #define DODECAHEDRON_NUM_VERT 20
595 #define DODECAHEDRON_NUM_FACES 12
596 #define DODECAHEDRON_NUM_EDGE_PER_FACE 5
597 #define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
598 #define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
599 #define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
600 /* Vertex Coordinates */
601 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
603 0.0f, 1.61803398875f, 0.61803398875f,
605 -0.61803398875f, 0.0f, 1.61803398875f,
606 0.61803398875f, 0.0f, 1.61803398875f,
608 0.0f, 1.61803398875f, -0.61803398875f,
610 0.61803398875f, 0.0f, -1.61803398875f,
611 -0.61803398875f, 0.0f, -1.61803398875f,
612 - 1.0f, 1.0f, - 1.0f,
613 0.0f, -1.61803398875f, 0.61803398875f,
615 - 1.0f, - 1.0f, 1.0f,
616 0.0f, -1.61803398875f, -0.61803398875f,
617 - 1.0f, - 1.0f, - 1.0f,
618 1.0f, - 1.0f, - 1.0f,
619 1.61803398875f, -0.61803398875f, 0.0f,
620 1.61803398875f, 0.61803398875f, 0.0f,
621 -1.61803398875f, 0.61803398875f, 0.0f,
622 -1.61803398875f, -0.61803398875f, 0.0f
625 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
627 0.0f, 0.525731112119f, 0.850650808354f,
628 0.0f, 0.525731112119f, -0.850650808354f,
629 0.0f, -0.525731112119f, 0.850650808354f,
630 0.0f, -0.525731112119f, -0.850650808354f,
632 0.850650808354f, 0.0f, 0.525731112119f,
633 -0.850650808354f, 0.0f, 0.525731112119f,
634 0.850650808354f, 0.0f, -0.525731112119f,
635 -0.850650808354f, 0.0f, -0.525731112119f,
637 0.525731112119f, 0.850650808354f, 0.0f,
638 0.525731112119f, -0.850650808354f, 0.0f,
639 -0.525731112119f, 0.850650808354f, 0.0f,
640 -0.525731112119f, -0.850650808354f, 0.0f,
644 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
661 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
664 /* -- Icosahedron -- */
665 #define ICOSAHEDRON_NUM_VERT 12
666 #define ICOSAHEDRON_NUM_FACES 20
667 #define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
668 #define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
669 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
670 #define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
671 /* Vertex Coordinates */
672 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
675 0.447213595500f, 0.894427191000f, 0.0f,
676 0.447213595500f, 0.276393202252f, 0.850650808354f,
677 0.447213595500f, -0.723606797748f, 0.525731112119f,
678 0.447213595500f, -0.723606797748f, -0.525731112119f,
679 0.447213595500f, 0.276393202252f, -0.850650808354f,
680 -0.447213595500f, -0.894427191000f, 0.0f,
681 -0.447213595500f, -0.276393202252f, 0.850650808354f,
682 -0.447213595500f, 0.723606797748f, 0.525731112119f,
683 -0.447213595500f, 0.723606797748f, -0.525731112119f,
684 -0.447213595500f, -0.276393202252f, -0.850650808354f,
688 * 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] ) ;
689 * 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] ) ;
690 * 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] ) ;
692 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
694 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
695 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
696 0.760845213033849f, -0.581234022404097f, 0.0f,
697 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
698 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
699 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
700 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
701 0.179611190633958f, -0.940456403667806f, 0.0f,
702 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
703 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
704 -0.179611190633958f, 0.940456403667806f, 0.0f,
705 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
706 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
707 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
708 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
709 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
710 -0.760845213033849f, 0.581234022404097f, 0.0f,
711 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
712 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
713 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
717 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
740 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
742 /* -- Octahedron -- */
743 #define OCTAHEDRON_NUM_VERT 6
744 #define OCTAHEDRON_NUM_FACES 8
745 #define OCTAHEDRON_NUM_EDGE_PER_FACE 3
746 #define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
747 #define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
748 #define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
750 /* Vertex Coordinates */
751 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
762 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
764 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
765 0.577350269189f, 0.577350269189f,-0.577350269189f,
766 0.577350269189f,-0.577350269189f, 0.577350269189f,
767 0.577350269189f,-0.577350269189f,-0.577350269189f,
768 -0.577350269189f, 0.577350269189f, 0.577350269189f,
769 -0.577350269189f, 0.577350269189f,-0.577350269189f,
770 -0.577350269189f,-0.577350269189f, 0.577350269189f,
771 -0.577350269189f,-0.577350269189f,-0.577350269189f
776 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
787 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
789 /* -- RhombicDodecahedron -- */
790 #define RHOMBICDODECAHEDRON_NUM_VERT 14
791 #define RHOMBICDODECAHEDRON_NUM_FACES 12
792 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
793 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
794 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
795 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
797 /* Vertex Coordinates */
798 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
801 0.707106781187f, 0.0f, 0.5f,
802 0.0f, 0.707106781187f, 0.5f,
803 -0.707106781187f, 0.0f, 0.5f,
804 0.0f, -0.707106781187f, 0.5f,
805 0.707106781187f, 0.707106781187f, 0.0f,
806 -0.707106781187f, 0.707106781187f, 0.0f,
807 -0.707106781187f, -0.707106781187f, 0.0f,
808 0.707106781187f, -0.707106781187f, 0.0f,
809 0.707106781187f, 0.0f, -0.5f,
810 0.0f, 0.707106781187f, -0.5f,
811 -0.707106781187f, 0.0f, -0.5f,
812 0.0f, -0.707106781187f, -0.5f,
816 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
818 0.353553390594f, 0.353553390594f, 0.5f,
819 -0.353553390594f, 0.353553390594f, 0.5f,
820 -0.353553390594f, -0.353553390594f, 0.5f,
821 0.353553390594f, -0.353553390594f, 0.5f,
826 0.353553390594f, 0.353553390594f, -0.5f,
827 -0.353553390594f, 0.353553390594f, -0.5f,
828 -0.353553390594f, -0.353553390594f, -0.5f,
829 0.353553390594f, -0.353553390594f, -0.5f
833 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
848 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
850 /* -- Tetrahedron -- */
851 /* Magic Numbers: r0 = ( 1, 0, 0 )
852 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
853 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
854 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
855 * |r0| = |r1| = |r2| = |r3| = 1
856 * Distance between any two points is 2 sqrt(6) / 3
858 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
860 #define TETRAHEDRON_NUM_VERT 4
861 #define TETRAHEDRON_NUM_FACES 4
862 #define TETRAHEDRON_NUM_EDGE_PER_FACE 3
863 #define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
864 #define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
865 #define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
867 /* Vertex Coordinates */
868 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
871 -0.333333333333f, 0.942809041582f, 0.0f,
872 -0.333333333333f, -0.471404520791f, 0.816496580928f,
873 -0.333333333333f, -0.471404520791f, -0.816496580928f
876 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
879 0.333333333333f, -0.942809041582f, 0.0f,
880 0.333333333333f, 0.471404520791f, -0.816496580928f,
881 0.333333333333f, 0.471404520791f, 0.816496580928f
885 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
892 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
894 /* -- Sierpinski Sponge -- */
895 static unsigned int ipow (int x, unsigned int y)
897 return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2);
900 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
903 if ( numLevels == 0 )
905 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
908 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
909 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
911 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
912 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
914 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
915 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
916 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
918 normals [outIdx ] = tetrahedron_n[normIdx ];
919 normals [outIdx+1] = tetrahedron_n[normIdx+1];
920 normals [outIdx+2] = tetrahedron_n[normIdx+2];
924 else if ( numLevels > 0 )
926 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
927 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
929 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
932 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
933 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
934 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
935 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
940 /* -- Now the various non-polyhedra (shapes involving circles) -- */
942 * Compute lookup table of cos and sin values forming a circle
943 * (or half circle if halfCircle==TRUE)
946 * It is the responsibility of the caller to free these tables
947 * The size of the table is (n+1) to form a connected loop
948 * The last entry is exactly the same as the first
949 * The sign of n can be flipped to get the reverse loop
951 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
955 /* Table size, the sign of n flips the circle direction */
956 const int size = abs(n);
958 /* Determine the angle between samples */
959 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
961 /* Allocate memory for n samples, plus duplicate of first entry at the end */
962 *sint = malloc(sizeof(GLfloat) * (size+1));
963 *cost = malloc(sizeof(GLfloat) * (size+1));
965 /* Bail out if memory allocation fails, fgError never returns */
966 if (!(*sint) || !(*cost))
970 fgError("Failed to allocate memory in fghCircleTable");
973 /* Compute cos and sin around the circle */
977 for (i=1; i<size; i++)
979 (*sint)[i] = (GLfloat)sin(angle*i);
980 (*cost)[i] = (GLfloat)cos(angle*i);
986 (*sint)[size] = 0.0f; /* sin PI */
987 (*cost)[size] = -1.0f; /* cos PI */
991 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
992 (*sint)[size] = (*sint)[0];
993 (*cost)[size] = (*cost)[0];
997 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
1000 int idx = 0; /* idx into vertex/normal buffer */
1003 /* Pre-computed circle */
1004 GLfloat *sint1,*cost1;
1005 GLfloat *sint2,*cost2;
1007 /* number of unique vertices */
1008 if (slices==0 || stacks<2)
1010 /* nothing to generate */
1014 *nVert = slices*(stacks-1)+2;
1015 if ((*nVert) > 65535)
1017 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1019 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1021 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
1023 /* precompute values on unit circle */
1024 fghCircleTable(&sint1,&cost1,-slices,FALSE);
1025 fghCircleTable(&sint2,&cost2, stacks,TRUE);
1027 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1028 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1029 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1030 if (!(*vertices) || !(*normals))
1034 fgError("Failed to allocate memory in fghGenerateSphere");
1038 (*vertices)[0] = 0.f;
1039 (*vertices)[1] = 0.f;
1040 (*vertices)[2] = radius;
1041 (*normals )[0] = 0.f;
1042 (*normals )[1] = 0.f;
1043 (*normals )[2] = 1.f;
1047 for( i=1; i<stacks; i++ )
1049 for(j=0; j<slices; j++, idx+=3)
1051 x = cost1[j]*sint2[i];
1052 y = sint1[j]*sint2[i];
1055 (*vertices)[idx ] = x*radius;
1056 (*vertices)[idx+1] = y*radius;
1057 (*vertices)[idx+2] = z*radius;
1058 (*normals )[idx ] = x;
1059 (*normals )[idx+1] = y;
1060 (*normals )[idx+2] = z;
1065 (*vertices)[idx ] = 0.f;
1066 (*vertices)[idx+1] = 0.f;
1067 (*vertices)[idx+2] = -radius;
1068 (*normals )[idx ] = 0.f;
1069 (*normals )[idx+1] = 0.f;
1070 (*normals )[idx+2] = -1.f;
1072 /* Done creating vertices, release sin and cos tables */
1079 void fghGenerateCone(
1080 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1081 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1085 int idx = 0; /* idx into vertex/normal buffer */
1087 /* Pre-computed circle */
1088 GLfloat *sint,*cost;
1090 /* Step in z and radius as stacks are drawn. */
1092 GLfloat r = (GLfloat)base;
1094 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1095 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1097 /* Scaling factors for vertex normals */
1098 const GLfloat cosn = (GLfloat) (height / sqrt( height * height + base * base ));
1099 const GLfloat sinn = (GLfloat) (base / sqrt( height * height + base * base ));
1103 /* number of unique vertices */
1104 if (slices==0 || stacks<1)
1106 /* nothing to generate */
1110 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1112 if ((*nVert) > 65535)
1114 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1116 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1118 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1120 /* Pre-computed circle */
1121 fghCircleTable(&sint,&cost,-slices,FALSE);
1123 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1124 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1125 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1126 if (!(*vertices) || !(*normals))
1130 fgError("Failed to allocate memory in fghGenerateCone");
1134 (*vertices)[0] = 0.f;
1135 (*vertices)[1] = 0.f;
1137 (*normals )[0] = 0.f;
1138 (*normals )[1] = 0.f;
1139 (*normals )[2] = -1.f;
1141 /* other on bottom (get normals right) */
1142 for (j=0; j<slices; j++, idx+=3)
1144 (*vertices)[idx ] = cost[j]*r;
1145 (*vertices)[idx+1] = sint[j]*r;
1146 (*vertices)[idx+2] = z;
1147 (*normals )[idx ] = 0.f;
1148 (*normals )[idx+1] = 0.f;
1149 (*normals )[idx+2] = -1.f;
1153 for (i=0; i<stacks+1; i++ )
1155 for (j=0; j<slices; j++, idx+=3)
1157 (*vertices)[idx ] = cost[j]*r;
1158 (*vertices)[idx+1] = sint[j]*r;
1159 (*vertices)[idx+2] = z;
1160 (*normals )[idx ] = cost[j]*sinn;
1161 (*normals )[idx+1] = sint[j]*sinn;
1162 (*normals )[idx+2] = cosn;
1169 /* Release sin and cos tables */
1174 void fghGenerateCylinder(
1175 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1176 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1180 int idx = 0; /* idx into vertex/normal buffer */
1182 /* Step in z as stacks are drawn. */
1183 GLfloat radf = (GLfloat)radius;
1185 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1187 /* Pre-computed circle */
1188 GLfloat *sint,*cost;
1190 /* number of unique vertices */
1191 if (slices==0 || stacks<1)
1193 /* nothing to generate */
1197 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1199 if ((*nVert) > 65535)
1201 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1203 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1205 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1207 /* Pre-computed circle */
1208 fghCircleTable(&sint,&cost,-slices,FALSE);
1210 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1211 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1212 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1213 if (!(*vertices) || !(*normals))
1217 fgError("Failed to allocate memory in fghGenerateCylinder");
1222 (*vertices)[0] = 0.f;
1223 (*vertices)[1] = 0.f;
1224 (*vertices)[2] = 0.f;
1225 (*normals )[0] = 0.f;
1226 (*normals )[1] = 0.f;
1227 (*normals )[2] = -1.f;
1229 /* other on top (get normals right) */
1230 for (j=0; j<slices; j++, idx+=3)
1232 (*vertices)[idx ] = cost[j]*radf;
1233 (*vertices)[idx+1] = sint[j]*radf;
1234 (*vertices)[idx+2] = z;
1235 (*normals )[idx ] = 0.f;
1236 (*normals )[idx+1] = 0.f;
1237 (*normals )[idx+2] = -1.f;
1241 for (i=0; i<stacks+1; i++ )
1243 for (j=0; j<slices; j++, idx+=3)
1245 (*vertices)[idx ] = cost[j]*radf;
1246 (*vertices)[idx+1] = sint[j]*radf;
1247 (*vertices)[idx+2] = z;
1248 (*normals )[idx ] = cost[j];
1249 (*normals )[idx+1] = sint[j];
1250 (*normals )[idx+2] = 0.f;
1256 /* other on bottom (get normals right) */
1258 for (j=0; j<slices; j++, idx+=3)
1260 (*vertices)[idx ] = cost[j]*radf;
1261 (*vertices)[idx+1] = sint[j]*radf;
1262 (*vertices)[idx+2] = z;
1263 (*normals )[idx ] = 0.f;
1264 (*normals )[idx+1] = 0.f;
1265 (*normals )[idx+2] = 1.f;
1269 (*vertices)[idx ] = 0.f;
1270 (*vertices)[idx+1] = 0.f;
1271 (*vertices)[idx+2] = height;
1272 (*normals )[idx ] = 0.f;
1273 (*normals )[idx+1] = 0.f;
1274 (*normals )[idx+2] = 1.f;
1276 /* Release sin and cos tables */
1281 void fghGenerateTorus(
1282 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1283 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1286 GLfloat iradius = (float)dInnerRadius;
1287 GLfloat oradius = (float)dOuterRadius;
1290 /* Pre-computed circle */
1291 GLfloat *spsi, *cpsi;
1292 GLfloat *sphi, *cphi;
1294 /* number of unique vertices */
1295 if (nSides<2 || nRings<2)
1297 /* nothing to generate */
1301 *nVert = nSides * nRings;
1303 if ((*nVert) > 65535)
1305 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1307 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1309 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1311 /* precompute values on unit circle */
1312 fghCircleTable(&spsi,&cpsi, nRings,FALSE);
1313 fghCircleTable(&sphi,&cphi,-nSides,FALSE);
1315 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1316 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1317 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1318 if (!(*vertices) || !(*normals))
1322 fgError("Failed to allocate memory in fghGenerateTorus");
1325 for( j=0; j<nRings; j++ )
1327 for( i=0; i<nSides; i++ )
1329 int offset = 3 * ( j * nSides + i ) ;
1331 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1332 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1333 (*vertices)[offset+2] = sphi[i] * iradius ;
1334 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1335 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1336 (*normals )[offset+2] = sphi[i] ;
1340 /* Release sin and cos tables */
1347 /* -- INTERNAL DRAWING functions --------------------------------------- */
1348 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1349 static void fgh##nameICaps( GLboolean useWireMode )\
1353 fgh##nameICaps##Generate();\
1354 name##Cached = GL_TRUE;\
1359 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1360 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1365 fghDrawGeometrySolid(name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ,\
1366 vertIdxs, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1369 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1370 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1372 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1379 cubeCached = GL_TRUE;
1384 /* Need to build new vertex list containing vertices for cube of different size */
1387 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1389 /* Bail out if memory allocation fails, fgError never returns */
1393 fgError("Failed to allocate memory in fghCube");
1396 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1397 vertices[i] = dSize*cube_verts[i];
1400 vertices = cube_verts;
1403 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1404 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1407 fghDrawGeometrySolid(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1408 cube_vertIdxs, 1, CUBE_VERT_PER_OBJ_TRI);
1411 /* cleanup allocated memory */
1415 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1416 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1417 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1418 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1419 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1421 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1425 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1426 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1427 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1431 /* Allocate memory */
1432 vertices = malloc(numVert*3 * sizeof(GLfloat));
1433 normals = malloc(numVert*3 * sizeof(GLfloat));
1434 /* Bail out if memory allocation fails, fgError never returns */
1435 if (!vertices || !normals)
1439 fgError("Failed to allocate memory in fghSierpinskiSponge");
1442 /* Generate elements */
1443 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1445 /* Draw and cleanup */
1447 fghDrawGeometryWire (vertices,normals,numVert,
1448 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1451 fghDrawGeometrySolid(vertices,normals,numVert,NULL,1,0);
1459 static void fghSphere( GLfloat radius, GLint slices, GLint stacks, GLboolean useWireMode )
1462 GLfloat *vertices, *normals;
1464 /* Generate vertices and normals */
1465 fghGenerateSphere(radius,slices,stacks,&vertices,&normals,&nVert);
1468 /* nothing to draw */
1473 GLushort *sliceIdx, *stackIdx;
1474 /* First, generate vertex index arrays for drawing with glDrawElements
1475 * We have a bunch of line_loops to draw for each stack, and a
1476 * bunch for each slice.
1479 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1480 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1481 if (!(stackIdx) || !(sliceIdx))
1485 fgError("Failed to allocate memory in fghSphere");
1488 /* generate for each stack */
1489 for (i=0,idx=0; i<stacks-1; i++)
1491 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1492 for (j=0; j<slices; j++, idx++)
1494 stackIdx[idx] = offset+j;
1498 /* generate for each slice */
1499 for (i=0,idx=0; i<slices; i++)
1501 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1502 sliceIdx[idx++] = 0; /* vertex on top */
1503 for (j=0; j<stacks-1; j++, idx++)
1505 sliceIdx[idx] = offset+j*slices;
1507 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1511 fghDrawGeometryWire(vertices,normals,nVert,
1512 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1513 stackIdx,stacks-1,slices);
1515 /* cleanup allocated memory */
1521 /* First, generate vertex index arrays for drawing with glDrawElements
1522 * All stacks, including top and bottom are covered with a triangle
1526 /* Create index vector */
1529 /* Allocate buffers for indices, bail out if memory allocation fails */
1530 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1534 fgError("Failed to allocate memory in fghSphere");
1538 for (j=0, idx=0; j<slices; j++, idx+=2)
1540 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1541 stripIdx[idx+1] = 0;
1543 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1544 stripIdx[idx+1] = 0;
1547 /* middle stacks: */
1548 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1549 for (i=0; i<stacks-2; i++, idx+=2)
1551 offset = 1+i*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1552 for (j=0; j<slices; j++, idx+=2)
1554 stripIdx[idx ] = offset+j+slices;
1555 stripIdx[idx+1] = offset+j;
1557 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1558 stripIdx[idx+1] = offset;
1562 offset = 1+(stacks-2)*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1563 for (j=0; j<slices; j++, idx+=2)
1565 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1566 stripIdx[idx+1] = offset+j;
1568 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1569 stripIdx[idx+1] = offset;
1573 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks,(slices+1)*2);
1575 /* cleanup allocated memory */
1579 /* cleanup allocated memory */
1584 static void fghCone( GLfloat base, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1587 GLfloat *vertices, *normals;
1589 /* Generate vertices and normals */
1590 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1591 fghGenerateCone(base,height,slices,stacks,&vertices,&normals,&nVert);
1594 /* nothing to draw */
1599 GLushort *sliceIdx, *stackIdx;
1600 /* First, generate vertex index arrays for drawing with glDrawElements
1601 * We have a bunch of line_loops to draw for each stack, and a
1602 * bunch for each slice.
1605 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1606 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1607 if (!(stackIdx) || !(sliceIdx))
1611 fgError("Failed to allocate memory in fghCone");
1614 /* generate for each stack */
1615 for (i=0,idx=0; i<stacks; i++)
1617 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1618 for (j=0; j<slices; j++, idx++)
1620 stackIdx[idx] = offset+j;
1624 /* generate for each slice */
1625 for (i=0,idx=0; i<slices; i++)
1627 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1628 sliceIdx[idx++] = offset+slices;
1629 sliceIdx[idx++] = offset+(stacks+1)*slices;
1633 fghDrawGeometryWire(vertices,normals,nVert,
1634 sliceIdx,1,slices*2,GL_LINES,
1635 stackIdx,stacks,slices);
1637 /* cleanup allocated memory */
1643 /* First, generate vertex index arrays for drawing with glDrawElements
1644 * All stacks, including top and bottom are covered with a triangle
1648 /* Create index vector */
1651 /* Allocate buffers for indices, bail out if memory allocation fails */
1652 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1656 fgError("Failed to allocate memory in fghCone");
1660 for (j=0, idx=0; j<slices; j++, idx+=2)
1663 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1665 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1666 stripIdx[idx+1] = 1;
1669 /* middle stacks: */
1670 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1671 for (i=0; i<stacks; i++, idx+=2)
1673 offset = 1+(i+1)*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1674 for (j=0; j<slices; j++, idx+=2)
1676 stripIdx[idx ] = offset+j;
1677 stripIdx[idx+1] = offset+j+slices;
1679 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1680 stripIdx[idx+1] = offset+slices;
1684 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+1,(slices+1)*2);
1686 /* cleanup allocated memory */
1690 /* cleanup allocated memory */
1695 static void fghCylinder( GLfloat radius, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1698 GLfloat *vertices, *normals;
1700 /* Generate vertices and normals */
1701 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1702 fghGenerateCylinder(radius,height,slices,stacks,&vertices,&normals,&nVert);
1705 /* nothing to draw */
1710 GLushort *sliceIdx, *stackIdx;
1711 /* First, generate vertex index arrays for drawing with glDrawElements
1712 * We have a bunch of line_loops to draw for each stack, and a
1713 * bunch for each slice.
1716 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1717 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1718 if (!(stackIdx) || !(sliceIdx))
1722 fgError("Failed to allocate memory in fghCylinder");
1725 /* generate for each stack */
1726 for (i=0,idx=0; i<stacks+1; i++)
1728 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1729 for (j=0; j<slices; j++, idx++)
1731 stackIdx[idx] = offset+j;
1735 /* generate for each slice */
1736 for (i=0,idx=0; i<slices; i++)
1738 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1739 sliceIdx[idx++] = offset+slices;
1740 sliceIdx[idx++] = offset+(stacks+1)*slices;
1744 fghDrawGeometryWire(vertices,normals,nVert,
1745 sliceIdx,1,slices*2,GL_LINES,
1746 stackIdx,stacks+1,slices);
1748 /* cleanup allocated memory */
1754 /* First, generate vertex index arrays for drawing with glDrawElements
1755 * All stacks, including top and bottom are covered with a triangle
1759 /* Create index vector */
1762 /* Allocate buffers for indices, bail out if memory allocation fails */
1763 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1767 fgError("Failed to allocate memory in fghCylinder");
1771 for (j=0, idx=0; j<slices; j++, idx+=2)
1774 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1776 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1777 stripIdx[idx+1] = 1;
1780 /* middle stacks: */
1781 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1782 for (i=0; i<stacks; i++, idx+=2)
1784 offset = 1+(i+1)*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1785 for (j=0; j<slices; j++, idx+=2)
1787 stripIdx[idx ] = offset+j;
1788 stripIdx[idx+1] = offset+j+slices;
1790 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1791 stripIdx[idx+1] = offset+slices;
1795 offset = 1+(stacks+2)*slices;
1796 for (j=0; j<slices; j++, idx+=2)
1798 stripIdx[idx ] = offset+j;
1799 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1801 stripIdx[idx ] = offset;
1802 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1805 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+2,(slices+1)*2);
1807 /* cleanup allocated memory */
1811 /* cleanup allocated memory */
1816 static void fghTorus( GLfloat dInnerRadius, GLfloat dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1819 GLfloat *vertices, *normals;
1821 /* Generate vertices and normals */
1822 fghGenerateTorus(dInnerRadius,dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1825 /* nothing to draw */
1830 GLushort *sideIdx, *ringIdx;
1831 /* First, generate vertex index arrays for drawing with glDrawElements
1832 * We have a bunch of line_loops to draw each side, and a
1833 * bunch for each ring.
1836 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1837 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1838 if (!(ringIdx) || !(sideIdx))
1842 fgError("Failed to allocate memory in fghTorus");
1845 /* generate for each ring */
1846 for( j=0,idx=0; j<nRings; j++ )
1847 for( i=0; i<nSides; i++, idx++ )
1848 ringIdx[idx] = j * nSides + i;
1850 /* generate for each side */
1851 for( i=0,idx=0; i<nSides; i++ )
1852 for( j=0; j<nRings; j++, idx++ )
1853 sideIdx[idx] = j * nSides + i;
1856 fghDrawGeometryWire(vertices,normals,nVert,
1857 ringIdx,nRings,nSides,GL_LINE_LOOP,
1858 sideIdx,nSides,nRings);
1860 /* cleanup allocated memory */
1866 /* First, generate vertex index arrays for drawing with glDrawElements
1867 * All stacks, including top and bottom are covered with a triangle
1872 /* Allocate buffers for indices, bail out if memory allocation fails */
1873 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
1877 fgError("Failed to allocate memory in fghTorus");
1880 for( i=0, idx=0; i<nSides; i++ )
1886 for( j=0; j<nRings; j++, idx+=2 )
1888 int offset = j * nSides + i;
1889 stripIdx[idx ] = offset;
1890 stripIdx[idx+1] = offset + ioff;
1892 /* repeat first to close off shape */
1894 stripIdx[idx+1] = i + ioff;
1899 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,nSides,(nRings+1)*2);
1901 /* cleanup allocated memory */
1905 /* cleanup allocated memory */
1911 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
1915 * Draws a solid sphere
1917 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
1919 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
1920 fghSphere((GLfloat)radius, slices, stacks, FALSE );
1924 * Draws a wire sphere
1926 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
1928 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
1929 fghSphere((GLfloat)radius, slices, stacks, TRUE );
1934 * Draws a solid cone
1936 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
1938 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
1939 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, FALSE );
1945 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
1947 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
1948 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, TRUE );
1953 * Draws a solid cylinder
1955 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
1957 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
1958 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, FALSE );
1962 * Draws a wire cylinder
1964 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
1966 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
1967 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, TRUE );
1971 * Draws a wire torus
1973 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1975 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
1976 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, TRUE);
1980 * Draws a solid torus
1982 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1984 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
1985 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, FALSE);
1990 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1991 /* Macro to generate interface functions */
1992 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
1993 void FGAPIENTRY glutWire##nameICaps( void )\
1995 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
1996 fgh##nameICaps( TRUE );\
1998 void FGAPIENTRY glutSolid##nameICaps( void )\
2000 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
2001 fgh##nameICaps( FALSE );\
2004 void FGAPIENTRY glutWireCube( double dSize )
2006 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
2007 fghCube( (GLfloat)dSize, TRUE );
2009 void FGAPIENTRY glutSolidCube( double dSize )
2011 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
2012 fghCube( (GLfloat)dSize, FALSE );
2015 DECLARE_SHAPE_INTERFACE(Dodecahedron)
2016 DECLARE_SHAPE_INTERFACE(Icosahedron)
2017 DECLARE_SHAPE_INTERFACE(Octahedron)
2018 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
2020 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
2022 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
2023 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
2025 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
2027 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
2028 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
2031 DECLARE_SHAPE_INTERFACE(Tetrahedron)
2034 /*** END OF FILE ***/