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 /* VC++6 in C mode doesn't have C99's sinf/cos/sqrtf */
35 #define sinf(x) (float)sin((double)(x))
38 #define cosf(x) (float)cos((double)(x))
41 #define sqrtf(x) (float)sqrt((double)(x))
44 /* declare for drawing using the different OpenGL versions here so we can
45 have a nice code order below */
46 #ifndef GL_ES_VERSION_2_0
47 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
48 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
49 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
51 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
52 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
54 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
55 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
56 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
57 GLint attribute_v_coord, GLint attribute_v_normal
59 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
60 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
61 GLint attribute_v_coord, GLint attribute_v_normal);
64 * Explanation of the functions has to be separate for the polyhedra and
65 * the non-polyhedra (objects with a circular cross-section).
67 * - We have only implemented the five platonic solids and the rhomboid
68 * dodecahedron. If you need more types of polyhedra, please see
70 * - Solids are drawn by glDrawArrays if composed of triangular faces
71 * (the tetrahedron, octahedron, and icosahedron), or are first
72 * decomposed into triangles and then drawn by glDrawElements if its
73 * faces are squares or pentagons (cube, dodecahedron and rhombic
74 * dodecahedron) as some vertices are repeated in that case.
75 * - WireFrame drawing is done using a GL_LINE_LOOP per face, and thus
76 * issuing one draw call per face. glDrawArrays is always used as no
77 * triangle decomposition is needed to draw faces. We use the "first"
78 * parameter in glDrawArrays to go from face to face.
81 * - We have implemented the sphere, cylinder, cone and torus.
82 * - All shapes are characterized by two parameters: the number of
83 * subdivisions along two axes used to construct the shape's vertices
84 * (e.g. stacks and slices for the sphere).
85 * As different subdivisions are most suitable for different shapes,
86 * and are thus also named differently, I wont provide general comments
88 * - Solids are drawn using glDrawArrays and GL_TRIANGLE_STRIP. Each
89 * strip covers one revolution around one of the two subdivision axes
91 * - WireFrame drawing is done for the subdivisions along the two axes
92 * separately, usually using GL_LINE_LOOP. Vertex index arrays are
93 * built containing the vertices to be drawn for each loop, which are
94 * then drawn using multiple calls to glDrawElements. As the number of
95 * subdivisions along the two axes is not guaranteed to be equal, the
96 * vertex indices for e.g. stacks and slices are stored in separate
97 * arrays, which makes the input to the drawing function a bit clunky,
98 * but allows for the same drawing function to be used for all shapes.
103 * Draw geometric shape in wire mode (only edges)
106 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
107 * The vertex coordinate and normal buffers, and the number of entries in
110 * a vertex indices buffer, optional (never passed for the polyhedra)
111 * GLsizei numParts, GLsizei numVertPerPart
112 * polyhedra: number of faces, and the number of vertices for drawing
114 * non-polyhedra: number of edges to draw for first subdivision (not
115 * necessarily equal to number of subdivisions requested by user, e.g.
116 * as each subdivision is enclosed by two edges), and number of
117 * vertices for drawing each
118 * numParts * numVertPerPart gives the number of entries in the vertex
121 * vertex drawing mode (e.g. always GL_LINE_LOOP for polyhedra, varies
123 * GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
124 * non-polyhedra only: same as the above, but now for subdivisions along
125 * the other axis. Always drawn as GL_LINE_LOOP.
127 * Feel free to contribute better naming ;)
129 static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
130 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
131 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
134 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
135 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
137 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
138 /* User requested a 2.0 draw */
139 fghDrawGeometryWire20(vertices, normals, numVertices,
140 vertIdxs, numParts, numVertPerPart, vertexMode,
141 vertIdxs2, numParts2, numVertPerPart2,
142 attribute_v_coord, attribute_v_normal);
143 #ifndef GL_ES_VERSION_2_0
145 fghDrawGeometryWire11(vertices, normals,
146 vertIdxs, numParts, numVertPerPart, vertexMode,
147 vertIdxs2, numParts2, numVertPerPart2);
151 /* Draw the geometric shape with filled triangles
154 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
155 * The vertex coordinate and normal buffers, and the number of entries in
158 * a vertex indices buffer, optional (not passed for the polyhedra with
160 * GLsizei numParts, GLsizei numVertPerPart
161 * polyhedra: not used for polyhedra with triangular faces
162 (numEdgePerFace==3), as each vertex+normal pair is drawn only once,
163 so no vertex indices are used.
164 Else, the shape was triangulated (DECOMPOSE_TO_TRIANGLE), leading to
165 reuse of some vertex+normal pairs, and thus the need to draw with
166 glDrawElements. numParts is always 1 in this case (we can draw the
167 whole object with one call to glDrawElements as the vertex index
168 array contains separate triangles), and numVertPerPart indicates
169 the number of vertex indices in the vertex array.
170 * non-polyhedra: number of parts (GL_TRIANGLE_STRIPs) to be drawn
171 separately (numParts calls to glDrawElements) to create the object.
172 numVertPerPart indicates the number of vertex indices to be
173 processed at each draw call.
174 * numParts * numVertPerPart gives the number of entries in the vertex
177 static void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
178 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
180 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
181 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
183 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
184 /* User requested a 2.0 draw */
185 fghDrawGeometrySolid20(vertices, normals, numVertices,
186 vertIdxs, numParts, numVertIdxsPerPart,
187 attribute_v_coord, attribute_v_normal);
188 #ifndef GL_ES_VERSION_2_0
190 fghDrawGeometrySolid11(vertices, normals, numVertices,
191 vertIdxs, numParts, numVertIdxsPerPart);
197 /* Version for OpenGL (ES) 1.1 */
198 #ifndef GL_ES_VERSION_2_0
199 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
200 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
201 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
206 glEnableClientState(GL_VERTEX_ARRAY);
207 glEnableClientState(GL_NORMAL_ARRAY);
209 glVertexPointer(3, GL_FLOAT, 0, vertices);
210 glNormalPointer(GL_FLOAT, 0, normals);
214 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
215 for (i=0; i<numParts; i++)
216 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
218 for (i=0; i<numParts; i++)
219 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
222 for (i=0; i<numParts2; i++)
223 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
225 glDisableClientState(GL_VERTEX_ARRAY);
226 glDisableClientState(GL_NORMAL_ARRAY);
230 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
231 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
235 glEnableClientState(GL_VERTEX_ARRAY);
236 glEnableClientState(GL_NORMAL_ARRAY);
238 glVertexPointer(3, GL_FLOAT, 0, vertices);
239 glNormalPointer(GL_FLOAT, 0, normals);
242 glDrawArrays(GL_TRIANGLES, 0, numVertices);
245 for (i=0; i<numParts; i++)
246 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
248 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
250 glDisableClientState(GL_VERTEX_ARRAY);
251 glDisableClientState(GL_NORMAL_ARRAY);
255 /* Version for OpenGL (ES) >= 2.0 */
256 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
257 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
258 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
259 GLint attribute_v_coord, GLint attribute_v_normal
262 GLuint vbo_coords = 0, vbo_normals = 0,
263 ibo_elements = 0, ibo_elements2 = 0;
264 GLsizei numVertIdxs = numParts * numVertPerPart;
265 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
268 if (numVertices > 0 && attribute_v_coord != -1) {
269 fghGenBuffers(1, &vbo_coords);
270 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
271 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
272 vertices, FGH_STATIC_DRAW);
275 if (numVertices > 0 && attribute_v_normal != -1) {
276 fghGenBuffers(1, &vbo_normals);
277 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
278 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
279 normals, FGH_STATIC_DRAW);
282 if (vertIdxs != NULL) {
283 fghGenBuffers(1, &ibo_elements);
284 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
285 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
286 vertIdxs, FGH_STATIC_DRAW);
287 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
290 if (vertIdxs2 != NULL) {
291 fghGenBuffers(1, &ibo_elements2);
292 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
293 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
294 vertIdxs2, FGH_STATIC_DRAW);
295 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
299 fghEnableVertexAttribArray(attribute_v_coord);
300 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
301 fghVertexAttribPointer(
302 attribute_v_coord, /* attribute */
303 3, /* number of elements per vertex, here (x,y,z) */
304 GL_FLOAT, /* the type of each element */
305 GL_FALSE, /* take our values as-is */
306 0, /* no extra data between each position */
307 0 /* offset of first element */
309 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
313 fghEnableVertexAttribArray(attribute_v_normal);
314 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
315 fghVertexAttribPointer(
316 attribute_v_normal, /* attribute */
317 3, /* number of elements per vertex, here (x,y,z) */
318 GL_FLOAT, /* the type of each element */
319 GL_FALSE, /* take our values as-is */
320 0, /* no extra data between each position */
321 0 /* offset of first element */
323 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
327 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
328 for (i=0; i<numParts; i++)
329 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
331 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
332 for (i=0; i<numParts; i++)
333 glDrawElements(vertexMode, numVertPerPart,
334 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
335 /* Clean existing bindings before clean-up */
336 /* Android showed instability otherwise */
337 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
341 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
342 for (i=0; i<numParts2; i++)
343 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
344 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
345 /* Clean existing bindings before clean-up */
346 /* Android showed instability otherwise */
347 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
351 fghDisableVertexAttribArray(attribute_v_coord);
352 if (vbo_normals != 0)
353 fghDisableVertexAttribArray(attribute_v_normal);
356 fghDeleteBuffers(1, &vbo_coords);
357 if (vbo_normals != 0)
358 fghDeleteBuffers(1, &vbo_normals);
359 if (ibo_elements != 0)
360 fghDeleteBuffers(1, &ibo_elements);
361 if (ibo_elements2 != 0)
362 fghDeleteBuffers(1, &ibo_elements2);
368 /* Version for OpenGL (ES) >= 2.0 */
369 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
370 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
371 GLint attribute_v_coord, GLint attribute_v_normal)
373 GLuint vbo_coords = 0, vbo_normals = 0, ibo_elements = 0;
374 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
377 if (numVertices > 0 && attribute_v_coord != -1) {
378 fghGenBuffers(1, &vbo_coords);
379 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
380 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
381 vertices, FGH_STATIC_DRAW);
382 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
385 if (numVertices > 0 && attribute_v_normal != -1) {
386 fghGenBuffers(1, &vbo_normals);
387 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
388 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
389 normals, FGH_STATIC_DRAW);
390 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
393 if (vertIdxs != NULL) {
394 fghGenBuffers(1, &ibo_elements);
395 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
396 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
397 vertIdxs, FGH_STATIC_DRAW);
398 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
402 fghEnableVertexAttribArray(attribute_v_coord);
403 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
404 fghVertexAttribPointer(
405 attribute_v_coord, /* attribute */
406 3, /* number of elements per vertex, here (x,y,z) */
407 GL_FLOAT, /* the type of each element */
408 GL_FALSE, /* take our values as-is */
409 0, /* no extra data between each position */
410 0 /* offset of first element */
412 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
416 fghEnableVertexAttribArray(attribute_v_normal);
417 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
418 fghVertexAttribPointer(
419 attribute_v_normal, /* attribute */
420 3, /* number of elements per vertex, here (x,y,z) */
421 GL_FLOAT, /* the type of each element */
422 GL_FALSE, /* take our values as-is */
423 0, /* no extra data between each position */
424 0 /* offset of first element */
426 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
429 if (vertIdxs == NULL) {
430 glDrawArrays(GL_TRIANGLES, 0, numVertices);
432 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
434 for (i=0; i<numParts; i++) {
435 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
438 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
440 /* Clean existing bindings before clean-up */
441 /* Android showed instability otherwise */
442 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
446 fghDisableVertexAttribArray(attribute_v_coord);
447 if (vbo_normals != 0)
448 fghDisableVertexAttribArray(attribute_v_normal);
451 fghDeleteBuffers(1, &vbo_coords);
452 if (vbo_normals != 0)
453 fghDeleteBuffers(1, &vbo_normals);
454 if (ibo_elements != 0)
455 fghDeleteBuffers(1, &ibo_elements);
461 * Generate all combinations of vertices and normals needed to draw object.
462 * Optional shape decomposition to triangles:
463 * We'll use glDrawElements to draw all shapes that are not naturally
464 * composed of triangles, so generate an index vector here, using the
465 * below sampling scheme.
466 * Be careful to keep winding of all triangles counter-clockwise,
467 * assuming that input has correct winding...
469 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
470 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
472 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
474 int i,j,numEdgeIdxPerFace;
475 GLubyte *vertSamps = NULL;
476 switch (numEdgePerFace)
479 /* nothing to do here, we'll draw with glDrawArrays */
482 vertSamps = vert4Decomp;
483 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
486 vertSamps = vert5Decomp;
487 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
491 * Build array with vertices using vertex coordinates and vertex indices
492 * Do same for normals.
493 * Need to do this because of different normals at shared vertices.
495 for (i=0; i<numFaces; i++)
498 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
499 for (j=0; j<numEdgePerFace; j++)
501 int outIdx = i*numEdgePerFace*3+j*3;
502 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
504 vertOut[outIdx ] = vertices[vertIdx ];
505 vertOut[outIdx+1] = vertices[vertIdx+1];
506 vertOut[outIdx+2] = vertices[vertIdx+2];
508 normOut[outIdx ] = normals [normIdx ];
509 normOut[outIdx+1] = normals [normIdx+1];
510 normOut[outIdx+2] = normals [normIdx+2];
513 /* generate vertex indices for each face */
515 for (j=0; j<numEdgeIdxPerFace; j++)
516 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
520 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
522 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
523 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
527 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
528 /* -- stuff that can be cached -- */
529 /* Cache of input to glDrawArrays or glDrawElements
530 * In general, we build arrays with all vertices or normals.
531 * We cant compress this and use glDrawElements as all combinations of
532 * vertices and normals are unique.
534 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
535 static GLboolean name##Cached = FALSE;\
536 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
537 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
538 static void fgh##nameICaps##Generate()\
540 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
541 name##_v, name##_vi, name##_n,\
542 name##_verts, name##_norms);\
544 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
545 static GLboolean name##Cached = FALSE;\
546 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
547 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
548 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
549 static void fgh##nameICaps##Generate()\
551 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
552 name##_v, name##_vi, name##_n,\
553 name##_verts, name##_norms, name##_vertIdxs);\
557 #define CUBE_NUM_VERT 8
558 #define CUBE_NUM_FACES 6
559 #define CUBE_NUM_EDGE_PER_FACE 4
560 #define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
561 #define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
562 #define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
563 /* Vertex Coordinates */
564 static GLfloat cube_v[CUBE_NUM_VERT*3] =
576 static GLfloat cube_n[CUBE_NUM_FACES*3] =
586 /* Vertex indices, as quads, before triangulation */
587 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
596 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
598 /* -- Dodecahedron -- */
599 /* Magic Numbers: It is possible to create a dodecahedron by attaching two
600 * pentagons to each face of of a cube. The coordinates of the points are:
601 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
602 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
603 * x = 0.61803398875 and z = 1.61803398875.
605 #define DODECAHEDRON_NUM_VERT 20
606 #define DODECAHEDRON_NUM_FACES 12
607 #define DODECAHEDRON_NUM_EDGE_PER_FACE 5
608 #define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
609 #define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
610 #define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
611 /* Vertex Coordinates */
612 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
614 0.0f, 1.61803398875f, 0.61803398875f,
616 -0.61803398875f, 0.0f, 1.61803398875f,
617 0.61803398875f, 0.0f, 1.61803398875f,
619 0.0f, 1.61803398875f, -0.61803398875f,
621 0.61803398875f, 0.0f, -1.61803398875f,
622 -0.61803398875f, 0.0f, -1.61803398875f,
623 - 1.0f, 1.0f, - 1.0f,
624 0.0f, -1.61803398875f, 0.61803398875f,
626 - 1.0f, - 1.0f, 1.0f,
627 0.0f, -1.61803398875f, -0.61803398875f,
628 - 1.0f, - 1.0f, - 1.0f,
629 1.0f, - 1.0f, - 1.0f,
630 1.61803398875f, -0.61803398875f, 0.0f,
631 1.61803398875f, 0.61803398875f, 0.0f,
632 -1.61803398875f, 0.61803398875f, 0.0f,
633 -1.61803398875f, -0.61803398875f, 0.0f
636 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
638 0.0f, 0.525731112119f, 0.850650808354f,
639 0.0f, 0.525731112119f, -0.850650808354f,
640 0.0f, -0.525731112119f, 0.850650808354f,
641 0.0f, -0.525731112119f, -0.850650808354f,
643 0.850650808354f, 0.0f, 0.525731112119f,
644 -0.850650808354f, 0.0f, 0.525731112119f,
645 0.850650808354f, 0.0f, -0.525731112119f,
646 -0.850650808354f, 0.0f, -0.525731112119f,
648 0.525731112119f, 0.850650808354f, 0.0f,
649 0.525731112119f, -0.850650808354f, 0.0f,
650 -0.525731112119f, 0.850650808354f, 0.0f,
651 -0.525731112119f, -0.850650808354f, 0.0f,
655 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
672 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
675 /* -- Icosahedron -- */
676 #define ICOSAHEDRON_NUM_VERT 12
677 #define ICOSAHEDRON_NUM_FACES 20
678 #define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
679 #define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
680 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
681 #define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
682 /* Vertex Coordinates */
683 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
686 0.447213595500f, 0.894427191000f, 0.0f,
687 0.447213595500f, 0.276393202252f, 0.850650808354f,
688 0.447213595500f, -0.723606797748f, 0.525731112119f,
689 0.447213595500f, -0.723606797748f, -0.525731112119f,
690 0.447213595500f, 0.276393202252f, -0.850650808354f,
691 -0.447213595500f, -0.894427191000f, 0.0f,
692 -0.447213595500f, -0.276393202252f, 0.850650808354f,
693 -0.447213595500f, 0.723606797748f, 0.525731112119f,
694 -0.447213595500f, 0.723606797748f, -0.525731112119f,
695 -0.447213595500f, -0.276393202252f, -0.850650808354f,
699 * 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] ) ;
700 * 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] ) ;
701 * 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] ) ;
703 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
705 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
706 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
707 0.760845213033849f, -0.581234022404097f, 0.0f,
708 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
709 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
710 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
711 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
712 0.179611190633958f, -0.940456403667806f, 0.0f,
713 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
714 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
715 -0.179611190633958f, 0.940456403667806f, 0.0f,
716 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
717 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
718 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
719 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
720 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
721 -0.760845213033849f, 0.581234022404097f, 0.0f,
722 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
723 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
724 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
728 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
751 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
753 /* -- Octahedron -- */
754 #define OCTAHEDRON_NUM_VERT 6
755 #define OCTAHEDRON_NUM_FACES 8
756 #define OCTAHEDRON_NUM_EDGE_PER_FACE 3
757 #define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
758 #define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
759 #define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
761 /* Vertex Coordinates */
762 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
773 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
775 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
776 0.577350269189f, 0.577350269189f,-0.577350269189f,
777 0.577350269189f,-0.577350269189f, 0.577350269189f,
778 0.577350269189f,-0.577350269189f,-0.577350269189f,
779 -0.577350269189f, 0.577350269189f, 0.577350269189f,
780 -0.577350269189f, 0.577350269189f,-0.577350269189f,
781 -0.577350269189f,-0.577350269189f, 0.577350269189f,
782 -0.577350269189f,-0.577350269189f,-0.577350269189f
787 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
798 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
800 /* -- RhombicDodecahedron -- */
801 #define RHOMBICDODECAHEDRON_NUM_VERT 14
802 #define RHOMBICDODECAHEDRON_NUM_FACES 12
803 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
804 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
805 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
806 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
808 /* Vertex Coordinates */
809 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
812 0.707106781187f, 0.0f, 0.5f,
813 0.0f, 0.707106781187f, 0.5f,
814 -0.707106781187f, 0.0f, 0.5f,
815 0.0f, -0.707106781187f, 0.5f,
816 0.707106781187f, 0.707106781187f, 0.0f,
817 -0.707106781187f, 0.707106781187f, 0.0f,
818 -0.707106781187f, -0.707106781187f, 0.0f,
819 0.707106781187f, -0.707106781187f, 0.0f,
820 0.707106781187f, 0.0f, -0.5f,
821 0.0f, 0.707106781187f, -0.5f,
822 -0.707106781187f, 0.0f, -0.5f,
823 0.0f, -0.707106781187f, -0.5f,
827 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
829 0.353553390594f, 0.353553390594f, 0.5f,
830 -0.353553390594f, 0.353553390594f, 0.5f,
831 -0.353553390594f, -0.353553390594f, 0.5f,
832 0.353553390594f, -0.353553390594f, 0.5f,
837 0.353553390594f, 0.353553390594f, -0.5f,
838 -0.353553390594f, 0.353553390594f, -0.5f,
839 -0.353553390594f, -0.353553390594f, -0.5f,
840 0.353553390594f, -0.353553390594f, -0.5f
844 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
859 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
861 /* -- Tetrahedron -- */
862 /* Magic Numbers: r0 = ( 1, 0, 0 )
863 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
864 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
865 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
866 * |r0| = |r1| = |r2| = |r3| = 1
867 * Distance between any two points is 2 sqrt(6) / 3
869 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
871 #define TETRAHEDRON_NUM_VERT 4
872 #define TETRAHEDRON_NUM_FACES 4
873 #define TETRAHEDRON_NUM_EDGE_PER_FACE 3
874 #define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
875 #define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
876 #define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
878 /* Vertex Coordinates */
879 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
882 -0.333333333333f, 0.942809041582f, 0.0f,
883 -0.333333333333f, -0.471404520791f, 0.816496580928f,
884 -0.333333333333f, -0.471404520791f, -0.816496580928f
887 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
890 0.333333333333f, -0.942809041582f, 0.0f,
891 0.333333333333f, 0.471404520791f, -0.816496580928f,
892 0.333333333333f, 0.471404520791f, 0.816496580928f
896 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
903 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
905 /* -- Sierpinski Sponge -- */
906 static unsigned int ipow (int x, unsigned int y)
908 return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2);
911 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
914 if ( numLevels == 0 )
916 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
919 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
920 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
922 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
923 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
925 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
926 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
927 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
929 normals [outIdx ] = tetrahedron_n[normIdx ];
930 normals [outIdx+1] = tetrahedron_n[normIdx+1];
931 normals [outIdx+2] = tetrahedron_n[normIdx+2];
935 else if ( numLevels > 0 )
937 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
938 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
940 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
943 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
944 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
945 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
946 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
951 /* -- Now the various non-polyhedra (shapes involving circles) -- */
953 * Compute lookup table of cos and sin values forming a circle
954 * (or half circle if halfCircle==TRUE)
957 * It is the responsibility of the caller to free these tables
958 * The size of the table is (n+1) to form a connected loop
959 * The last entry is exactly the same as the first
960 * The sign of n can be flipped to get the reverse loop
962 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
966 /* Table size, the sign of n flips the circle direction */
967 const int size = abs(n);
969 /* Determine the angle between samples */
970 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
972 /* Allocate memory for n samples, plus duplicate of first entry at the end */
973 *sint = malloc(sizeof(GLfloat) * (size+1));
974 *cost = malloc(sizeof(GLfloat) * (size+1));
976 /* Bail out if memory allocation fails, fgError never returns */
977 if (!(*sint) || !(*cost))
981 fgError("Failed to allocate memory in fghCircleTable");
984 /* Compute cos and sin around the circle */
988 for (i=1; i<size; i++)
990 (*sint)[i] = sinf(angle*i);
991 (*cost)[i] = cosf(angle*i);
997 (*sint)[size] = 0.0f; /* sin PI */
998 (*cost)[size] = -1.0f; /* cos PI */
1002 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
1003 (*sint)[size] = (*sint)[0];
1004 (*cost)[size] = (*cost)[0];
1008 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
1011 int idx = 0; /* idx into vertex/normal buffer */
1014 /* Pre-computed circle */
1015 GLfloat *sint1,*cost1;
1016 GLfloat *sint2,*cost2;
1018 /* number of unique vertices */
1019 if (slices==0 || stacks<2)
1021 /* nothing to generate */
1025 *nVert = slices*(stacks-1)+2;
1026 if ((*nVert) > 65535)
1028 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1030 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1032 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
1034 /* precompute values on unit circle */
1035 fghCircleTable(&sint1,&cost1,-slices,FALSE);
1036 fghCircleTable(&sint2,&cost2, stacks,TRUE);
1038 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1039 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1040 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1041 if (!(*vertices) || !(*normals))
1045 fgError("Failed to allocate memory in fghGenerateSphere");
1049 (*vertices)[0] = 0.f;
1050 (*vertices)[1] = 0.f;
1051 (*vertices)[2] = radius;
1052 (*normals )[0] = 0.f;
1053 (*normals )[1] = 0.f;
1054 (*normals )[2] = 1.f;
1058 for( i=1; i<stacks; i++ )
1060 for(j=0; j<slices; j++, idx+=3)
1062 x = cost1[j]*sint2[i];
1063 y = sint1[j]*sint2[i];
1066 (*vertices)[idx ] = x*radius;
1067 (*vertices)[idx+1] = y*radius;
1068 (*vertices)[idx+2] = z*radius;
1069 (*normals )[idx ] = x;
1070 (*normals )[idx+1] = y;
1071 (*normals )[idx+2] = z;
1076 (*vertices)[idx ] = 0.f;
1077 (*vertices)[idx+1] = 0.f;
1078 (*vertices)[idx+2] = -radius;
1079 (*normals )[idx ] = 0.f;
1080 (*normals )[idx+1] = 0.f;
1081 (*normals )[idx+2] = -1.f;
1083 /* Done creating vertices, release sin and cos tables */
1090 void fghGenerateCone(
1091 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1092 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1096 int idx = 0; /* idx into vertex/normal buffer */
1098 /* Pre-computed circle */
1099 GLfloat *sint,*cost;
1101 /* Step in z and radius as stacks are drawn. */
1103 GLfloat r = (GLfloat)base;
1105 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1106 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1108 /* Scaling factors for vertex normals */
1109 const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
1110 const GLfloat sinn = ( (GLfloat)base / sqrtf( height * height + base * base ));
1114 /* number of unique vertices */
1115 if (slices==0 || stacks<1)
1117 /* nothing to generate */
1121 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1123 if ((*nVert) > 65535)
1125 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1127 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1129 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1131 /* Pre-computed circle */
1132 fghCircleTable(&sint,&cost,-slices,FALSE);
1134 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1135 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1136 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1137 if (!(*vertices) || !(*normals))
1141 fgError("Failed to allocate memory in fghGenerateCone");
1145 (*vertices)[0] = 0.f;
1146 (*vertices)[1] = 0.f;
1148 (*normals )[0] = 0.f;
1149 (*normals )[1] = 0.f;
1150 (*normals )[2] = -1.f;
1152 /* other on bottom (get normals right) */
1153 for (j=0; j<slices; j++, idx+=3)
1155 (*vertices)[idx ] = cost[j]*r;
1156 (*vertices)[idx+1] = sint[j]*r;
1157 (*vertices)[idx+2] = z;
1158 (*normals )[idx ] = 0.f;
1159 (*normals )[idx+1] = 0.f;
1160 (*normals )[idx+2] = -1.f;
1164 for (i=0; i<stacks+1; i++ )
1166 for (j=0; j<slices; j++, idx+=3)
1168 (*vertices)[idx ] = cost[j]*r;
1169 (*vertices)[idx+1] = sint[j]*r;
1170 (*vertices)[idx+2] = z;
1171 (*normals )[idx ] = cost[j]*sinn;
1172 (*normals )[idx+1] = sint[j]*sinn;
1173 (*normals )[idx+2] = cosn;
1180 /* Release sin and cos tables */
1185 void fghGenerateCylinder(
1186 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1187 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1191 int idx = 0; /* idx into vertex/normal buffer */
1193 /* Step in z as stacks are drawn. */
1194 GLfloat radf = (GLfloat)radius;
1196 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1198 /* Pre-computed circle */
1199 GLfloat *sint,*cost;
1201 /* number of unique vertices */
1202 if (slices==0 || stacks<1)
1204 /* nothing to generate */
1208 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1210 if ((*nVert) > 65535)
1212 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1214 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1216 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1218 /* Pre-computed circle */
1219 fghCircleTable(&sint,&cost,-slices,FALSE);
1221 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1222 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1223 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1224 if (!(*vertices) || !(*normals))
1228 fgError("Failed to allocate memory in fghGenerateCylinder");
1233 (*vertices)[0] = 0.f;
1234 (*vertices)[1] = 0.f;
1235 (*vertices)[2] = 0.f;
1236 (*normals )[0] = 0.f;
1237 (*normals )[1] = 0.f;
1238 (*normals )[2] = -1.f;
1240 /* other on top (get normals right) */
1241 for (j=0; j<slices; j++, idx+=3)
1243 (*vertices)[idx ] = cost[j]*radf;
1244 (*vertices)[idx+1] = sint[j]*radf;
1245 (*vertices)[idx+2] = z;
1246 (*normals )[idx ] = 0.f;
1247 (*normals )[idx+1] = 0.f;
1248 (*normals )[idx+2] = -1.f;
1252 for (i=0; i<stacks+1; i++ )
1254 for (j=0; j<slices; j++, idx+=3)
1256 (*vertices)[idx ] = cost[j]*radf;
1257 (*vertices)[idx+1] = sint[j]*radf;
1258 (*vertices)[idx+2] = z;
1259 (*normals )[idx ] = cost[j];
1260 (*normals )[idx+1] = sint[j];
1261 (*normals )[idx+2] = 0.f;
1267 /* other on bottom (get normals right) */
1269 for (j=0; j<slices; j++, idx+=3)
1271 (*vertices)[idx ] = cost[j]*radf;
1272 (*vertices)[idx+1] = sint[j]*radf;
1273 (*vertices)[idx+2] = z;
1274 (*normals )[idx ] = 0.f;
1275 (*normals )[idx+1] = 0.f;
1276 (*normals )[idx+2] = 1.f;
1280 (*vertices)[idx ] = 0.f;
1281 (*vertices)[idx+1] = 0.f;
1282 (*vertices)[idx+2] = height;
1283 (*normals )[idx ] = 0.f;
1284 (*normals )[idx+1] = 0.f;
1285 (*normals )[idx+2] = 1.f;
1287 /* Release sin and cos tables */
1292 void fghGenerateTorus(
1293 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1294 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1297 GLfloat iradius = (float)dInnerRadius;
1298 GLfloat oradius = (float)dOuterRadius;
1301 /* Pre-computed circle */
1302 GLfloat *spsi, *cpsi;
1303 GLfloat *sphi, *cphi;
1305 /* number of unique vertices */
1306 if (nSides<2 || nRings<2)
1308 /* nothing to generate */
1312 *nVert = nSides * nRings;
1314 if ((*nVert) > 65535)
1316 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1318 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1320 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1322 /* precompute values on unit circle */
1323 fghCircleTable(&spsi,&cpsi, nRings,FALSE);
1324 fghCircleTable(&sphi,&cphi,-nSides,FALSE);
1326 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1327 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1328 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1329 if (!(*vertices) || !(*normals))
1333 fgError("Failed to allocate memory in fghGenerateTorus");
1336 for( j=0; j<nRings; j++ )
1338 for( i=0; i<nSides; i++ )
1340 int offset = 3 * ( j * nSides + i ) ;
1342 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1343 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1344 (*vertices)[offset+2] = sphi[i] * iradius ;
1345 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1346 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1347 (*normals )[offset+2] = sphi[i] ;
1351 /* Release sin and cos tables */
1358 /* -- INTERNAL DRAWING functions --------------------------------------- */
1359 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1360 static void fgh##nameICaps( GLboolean useWireMode )\
1364 fgh##nameICaps##Generate();\
1365 name##Cached = GL_TRUE;\
1370 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1371 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1376 fghDrawGeometrySolid(name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ,\
1377 vertIdxs, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1380 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1381 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1383 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1390 cubeCached = GL_TRUE;
1395 /* Need to build new vertex list containing vertices for cube of different size */
1398 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1400 /* Bail out if memory allocation fails, fgError never returns */
1404 fgError("Failed to allocate memory in fghCube");
1407 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1408 vertices[i] = dSize*cube_verts[i];
1411 vertices = cube_verts;
1414 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1415 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1418 fghDrawGeometrySolid(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1419 cube_vertIdxs, 1, CUBE_VERT_PER_OBJ_TRI);
1422 /* cleanup allocated memory */
1426 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1427 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1428 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1429 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1430 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1432 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1436 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1437 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1438 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1442 /* Allocate memory */
1443 vertices = malloc(numVert*3 * sizeof(GLfloat));
1444 normals = malloc(numVert*3 * sizeof(GLfloat));
1445 /* Bail out if memory allocation fails, fgError never returns */
1446 if (!vertices || !normals)
1450 fgError("Failed to allocate memory in fghSierpinskiSponge");
1453 /* Generate elements */
1454 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1456 /* Draw and cleanup */
1458 fghDrawGeometryWire (vertices,normals,numVert,
1459 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1462 fghDrawGeometrySolid(vertices,normals,numVert,NULL,1,0);
1470 static void fghSphere( GLfloat radius, GLint slices, GLint stacks, GLboolean useWireMode )
1473 GLfloat *vertices, *normals;
1475 /* Generate vertices and normals */
1476 fghGenerateSphere(radius,slices,stacks,&vertices,&normals,&nVert);
1479 /* nothing to draw */
1484 GLushort *sliceIdx, *stackIdx;
1485 /* First, generate vertex index arrays for drawing with glDrawElements
1486 * We have a bunch of line_loops to draw for each stack, and a
1487 * bunch for each slice.
1490 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1491 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1492 if (!(stackIdx) || !(sliceIdx))
1496 fgError("Failed to allocate memory in fghSphere");
1499 /* generate for each stack */
1500 for (i=0,idx=0; i<stacks-1; i++)
1502 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1503 for (j=0; j<slices; j++, idx++)
1505 stackIdx[idx] = offset+j;
1509 /* generate for each slice */
1510 for (i=0,idx=0; i<slices; i++)
1512 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1513 sliceIdx[idx++] = 0; /* vertex on top */
1514 for (j=0; j<stacks-1; j++, idx++)
1516 sliceIdx[idx] = offset+j*slices;
1518 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1522 fghDrawGeometryWire(vertices,normals,nVert,
1523 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1524 stackIdx,stacks-1,slices);
1526 /* cleanup allocated memory */
1532 /* First, generate vertex index arrays for drawing with glDrawElements
1533 * All stacks, including top and bottom are covered with a triangle
1537 /* Create index vector */
1540 /* Allocate buffers for indices, bail out if memory allocation fails */
1541 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1545 fgError("Failed to allocate memory in fghSphere");
1549 for (j=0, idx=0; j<slices; j++, idx+=2)
1551 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1552 stripIdx[idx+1] = 0;
1554 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1555 stripIdx[idx+1] = 0;
1558 /* middle stacks: */
1559 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1560 for (i=0; i<stacks-2; i++, idx+=2)
1562 offset = 1+i*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 ] = offset+j+slices;
1566 stripIdx[idx+1] = offset+j;
1568 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1569 stripIdx[idx+1] = offset;
1573 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 */
1574 for (j=0; j<slices; j++, idx+=2)
1576 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1577 stripIdx[idx+1] = offset+j;
1579 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1580 stripIdx[idx+1] = offset;
1584 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks,(slices+1)*2);
1586 /* cleanup allocated memory */
1590 /* cleanup allocated memory */
1595 static void fghCone( GLfloat base, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1598 GLfloat *vertices, *normals;
1600 /* Generate vertices and normals */
1601 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1602 fghGenerateCone(base,height,slices,stacks,&vertices,&normals,&nVert);
1605 /* nothing to draw */
1610 GLushort *sliceIdx, *stackIdx;
1611 /* First, generate vertex index arrays for drawing with glDrawElements
1612 * We have a bunch of line_loops to draw for each stack, and a
1613 * bunch for each slice.
1616 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1617 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1618 if (!(stackIdx) || !(sliceIdx))
1622 fgError("Failed to allocate memory in fghCone");
1625 /* generate for each stack */
1626 for (i=0,idx=0; i<stacks; i++)
1628 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1629 for (j=0; j<slices; j++, idx++)
1631 stackIdx[idx] = offset+j;
1635 /* generate for each slice */
1636 for (i=0,idx=0; i<slices; i++)
1638 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1639 sliceIdx[idx++] = offset+slices;
1640 sliceIdx[idx++] = offset+(stacks+1)*slices;
1644 fghDrawGeometryWire(vertices,normals,nVert,
1645 sliceIdx,1,slices*2,GL_LINES,
1646 stackIdx,stacks,slices);
1648 /* cleanup allocated memory */
1654 /* First, generate vertex index arrays for drawing with glDrawElements
1655 * All stacks, including top and bottom are covered with a triangle
1659 /* Create index vector */
1662 /* Allocate buffers for indices, bail out if memory allocation fails */
1663 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1667 fgError("Failed to allocate memory in fghCone");
1671 for (j=0, idx=0; j<slices; j++, idx+=2)
1674 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1676 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1677 stripIdx[idx+1] = 1;
1680 /* middle stacks: */
1681 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1682 for (i=0; i<stacks; i++, idx+=2)
1684 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 */
1685 for (j=0; j<slices; j++, idx+=2)
1687 stripIdx[idx ] = offset+j;
1688 stripIdx[idx+1] = offset+j+slices;
1690 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1691 stripIdx[idx+1] = offset+slices;
1695 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+1,(slices+1)*2);
1697 /* cleanup allocated memory */
1701 /* cleanup allocated memory */
1706 static void fghCylinder( GLfloat radius, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1709 GLfloat *vertices, *normals;
1711 /* Generate vertices and normals */
1712 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1713 fghGenerateCylinder(radius,height,slices,stacks,&vertices,&normals,&nVert);
1716 /* nothing to draw */
1721 GLushort *sliceIdx, *stackIdx;
1722 /* First, generate vertex index arrays for drawing with glDrawElements
1723 * We have a bunch of line_loops to draw for each stack, and a
1724 * bunch for each slice.
1727 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1728 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1729 if (!(stackIdx) || !(sliceIdx))
1733 fgError("Failed to allocate memory in fghCylinder");
1736 /* generate for each stack */
1737 for (i=0,idx=0; i<stacks+1; i++)
1739 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1740 for (j=0; j<slices; j++, idx++)
1742 stackIdx[idx] = offset+j;
1746 /* generate for each slice */
1747 for (i=0,idx=0; i<slices; i++)
1749 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1750 sliceIdx[idx++] = offset+slices;
1751 sliceIdx[idx++] = offset+(stacks+1)*slices;
1755 fghDrawGeometryWire(vertices,normals,nVert,
1756 sliceIdx,1,slices*2,GL_LINES,
1757 stackIdx,stacks+1,slices);
1759 /* cleanup allocated memory */
1765 /* First, generate vertex index arrays for drawing with glDrawElements
1766 * All stacks, including top and bottom are covered with a triangle
1770 /* Create index vector */
1773 /* Allocate buffers for indices, bail out if memory allocation fails */
1774 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1778 fgError("Failed to allocate memory in fghCylinder");
1782 for (j=0, idx=0; j<slices; j++, idx+=2)
1785 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1787 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1788 stripIdx[idx+1] = 1;
1791 /* middle stacks: */
1792 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1793 for (i=0; i<stacks; i++, idx+=2)
1795 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 */
1796 for (j=0; j<slices; j++, idx+=2)
1798 stripIdx[idx ] = offset+j;
1799 stripIdx[idx+1] = offset+j+slices;
1801 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1802 stripIdx[idx+1] = offset+slices;
1806 offset = 1+(stacks+2)*slices;
1807 for (j=0; j<slices; j++, idx+=2)
1809 stripIdx[idx ] = offset+j;
1810 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1812 stripIdx[idx ] = offset;
1813 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1816 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+2,(slices+1)*2);
1818 /* cleanup allocated memory */
1822 /* cleanup allocated memory */
1827 static void fghTorus( GLfloat dInnerRadius, GLfloat dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1830 GLfloat *vertices, *normals;
1832 /* Generate vertices and normals */
1833 fghGenerateTorus(dInnerRadius,dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1836 /* nothing to draw */
1841 GLushort *sideIdx, *ringIdx;
1842 /* First, generate vertex index arrays for drawing with glDrawElements
1843 * We have a bunch of line_loops to draw each side, and a
1844 * bunch for each ring.
1847 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1848 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1849 if (!(ringIdx) || !(sideIdx))
1853 fgError("Failed to allocate memory in fghTorus");
1856 /* generate for each ring */
1857 for( j=0,idx=0; j<nRings; j++ )
1858 for( i=0; i<nSides; i++, idx++ )
1859 ringIdx[idx] = j * nSides + i;
1861 /* generate for each side */
1862 for( i=0,idx=0; i<nSides; i++ )
1863 for( j=0; j<nRings; j++, idx++ )
1864 sideIdx[idx] = j * nSides + i;
1867 fghDrawGeometryWire(vertices,normals,nVert,
1868 ringIdx,nRings,nSides,GL_LINE_LOOP,
1869 sideIdx,nSides,nRings);
1871 /* cleanup allocated memory */
1877 /* First, generate vertex index arrays for drawing with glDrawElements
1878 * All stacks, including top and bottom are covered with a triangle
1883 /* Allocate buffers for indices, bail out if memory allocation fails */
1884 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
1888 fgError("Failed to allocate memory in fghTorus");
1891 for( i=0, idx=0; i<nSides; i++ )
1897 for( j=0; j<nRings; j++, idx+=2 )
1899 int offset = j * nSides + i;
1900 stripIdx[idx ] = offset;
1901 stripIdx[idx+1] = offset + ioff;
1903 /* repeat first to close off shape */
1905 stripIdx[idx+1] = i + ioff;
1910 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,nSides,(nRings+1)*2);
1912 /* cleanup allocated memory */
1916 /* cleanup allocated memory */
1922 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
1926 * Draws a solid sphere
1928 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
1930 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
1931 fghSphere((GLfloat)radius, slices, stacks, FALSE );
1935 * Draws a wire sphere
1937 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
1939 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
1940 fghSphere((GLfloat)radius, slices, stacks, TRUE );
1945 * Draws a solid cone
1947 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
1949 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
1950 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, FALSE );
1956 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
1958 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
1959 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, TRUE );
1964 * Draws a solid cylinder
1966 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
1968 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
1969 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, FALSE );
1973 * Draws a wire cylinder
1975 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
1977 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
1978 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, TRUE );
1982 * Draws a wire torus
1984 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1986 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
1987 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, TRUE);
1991 * Draws a solid torus
1993 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1995 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
1996 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, FALSE);
2001 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
2002 /* Macro to generate interface functions */
2003 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
2004 void FGAPIENTRY glutWire##nameICaps( void )\
2006 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
2007 fgh##nameICaps( TRUE );\
2009 void FGAPIENTRY glutSolid##nameICaps( void )\
2011 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
2012 fgh##nameICaps( FALSE );\
2015 void FGAPIENTRY glutWireCube( double dSize )
2017 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
2018 fghCube( (GLfloat)dSize, TRUE );
2020 void FGAPIENTRY glutSolidCube( double dSize )
2022 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
2023 fghCube( (GLfloat)dSize, FALSE );
2026 DECLARE_SHAPE_INTERFACE(Dodecahedron)
2027 DECLARE_SHAPE_INTERFACE(Icosahedron)
2028 DECLARE_SHAPE_INTERFACE(Octahedron)
2029 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
2031 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
2033 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
2034 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
2036 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
2038 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
2039 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
2042 DECLARE_SHAPE_INTERFACE(Tetrahedron)
2045 /*** END OF FILE ***/