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"
34 * Need more types of polyhedra? See CPolyhedron in MRPT
37 /* VC++6 in C mode doesn't have C99's sinf/cos/sqrtf */
39 #define sinf(x) (float)sin((double)(x))
42 #define cosf(x) (float)cos((double)(x))
45 #define sqrtf(x) (float)sqrt((double)(x))
48 /* General functions for drawing geometry
49 * Solids are drawn by glDrawArrays if composed of triangles, or by
50 * glDrawElements if consisting of squares or pentagons that were
51 * decomposed into triangles (some vertices are repeated in that case).
52 * WireFrame drawing will have to be done per face, using GL_LINE_LOOP and
53 * issuing one draw call per face. Always use glDrawArrays as no triangle
54 * decomposition needed. We use the "first" parameter in glDrawArrays to go
58 /** See comment for fghDrawGeometryWire **/
60 /* Version for OpenGL (ES) 1.1 */
61 #ifndef GL_ES_VERSION_2_0
62 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
63 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
64 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
69 glEnableClientState(GL_VERTEX_ARRAY);
70 glEnableClientState(GL_NORMAL_ARRAY);
72 glVertexPointer(3, GL_FLOAT, 0, vertices);
73 glNormalPointer(GL_FLOAT, 0, normals);
77 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
78 for (i=0; i<numParts; i++)
79 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
81 for (i=0; i<numParts; i++)
82 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
85 for (i=0; i<numParts2; i++)
86 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
88 glDisableClientState(GL_VERTEX_ARRAY);
89 glDisableClientState(GL_NORMAL_ARRAY);
93 /* Version for OpenGL (ES) >= 2.0 */
94 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
95 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
96 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
97 GLint attribute_v_coord, GLint attribute_v_normal
100 GLuint vbo_coords = 0, vbo_normals = 0,
101 ibo_elements = 0, ibo_elements2 = 0;
102 GLsizei numVertIdxs = numParts * numVertPerPart;
103 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
106 if (numVertices > 0 && attribute_v_coord != -1) {
107 fghGenBuffers(1, &vbo_coords);
108 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
109 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
110 vertices, FGH_STATIC_DRAW);
113 if (numVertices > 0 && attribute_v_normal != -1) {
114 fghGenBuffers(1, &vbo_normals);
115 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
116 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
117 normals, FGH_STATIC_DRAW);
120 if (vertIdxs != NULL) {
121 fghGenBuffers(1, &ibo_elements);
122 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
123 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
124 vertIdxs, FGH_STATIC_DRAW);
125 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
128 if (vertIdxs2 != NULL) {
129 fghGenBuffers(1, &ibo_elements2);
130 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
131 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
132 vertIdxs2, FGH_STATIC_DRAW);
133 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
137 fghEnableVertexAttribArray(attribute_v_coord);
138 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
139 fghVertexAttribPointer(
140 attribute_v_coord, /* attribute */
141 3, /* number of elements per vertex, here (x,y,z) */
142 GL_FLOAT, /* the type of each element */
143 GL_FALSE, /* take our values as-is */
144 0, /* no extra data between each position */
145 0 /* offset of first element */
147 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
151 fghEnableVertexAttribArray(attribute_v_normal);
152 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
153 fghVertexAttribPointer(
154 attribute_v_normal, /* attribute */
155 3, /* number of elements per vertex, here (x,y,z) */
156 GL_FLOAT, /* the type of each element */
157 GL_FALSE, /* take our values as-is */
158 0, /* no extra data between each position */
159 0 /* offset of first element */
161 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
165 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
166 for (i=0; i<numParts; i++)
167 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
169 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
170 for (i=0; i<numParts; i++)
171 glDrawElements(vertexMode, numVertPerPart,
172 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
173 /* Clean existing bindings before clean-up */
174 /* Android showed instability otherwise */
175 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
179 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
180 for (i=0; i<numParts2; i++)
181 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
182 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
183 /* Clean existing bindings before clean-up */
184 /* Android showed instability otherwise */
185 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
189 fghDisableVertexAttribArray(attribute_v_coord);
190 if (vbo_normals != 0)
191 fghDisableVertexAttribArray(attribute_v_normal);
194 fghDeleteBuffers(1, &vbo_coords);
195 if (vbo_normals != 0)
196 fghDeleteBuffers(1, &vbo_normals);
197 if (ibo_elements != 0)
198 fghDeleteBuffers(1, &ibo_elements);
199 if (ibo_elements2 != 0)
200 fghDeleteBuffers(1, &ibo_elements2);
204 * Draw geometric shape in wire mode (only edges)
206 * Arguments: the sphere, in wire mode, consists of multiple line
207 * loops for the stacks, and for the slices. The vertex indices for
208 * all slices are thrown together. numParts is how many separate loops
209 * are in the array, numVertIdxsPerPart is how many vertices there are
210 * per loop. For those suffixed with 2, its exactly the same
211 * principle, the number of stacks and slices is not the same.
213 * Feel free to contribute better naming ;)
215 * See comment for fghDrawGeometrySolid
217 static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
218 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
219 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
222 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
223 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
225 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
226 /* User requested a 2.0 draw */
227 fghDrawGeometryWire20(vertices, normals, numVertices,
228 vertIdxs, numParts, numVertPerPart, vertexMode,
229 vertIdxs2, numParts2, numVertPerPart2,
230 attribute_v_coord, attribute_v_normal);
231 #ifndef GL_ES_VERSION_2_0
233 fghDrawGeometryWire11(vertices, normals,
234 vertIdxs, numParts, numVertPerPart, vertexMode,
235 vertIdxs2, numParts2, numVertPerPart2);
240 /* Version for OpenGL (ES) 1.1 */
241 #ifndef GL_ES_VERSION_2_0
242 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLushort *vertIdxs,
243 GLsizei numVertices, GLsizei numParts, GLsizei numVertIdxsPerPart)
247 glEnableClientState(GL_VERTEX_ARRAY);
248 glEnableClientState(GL_NORMAL_ARRAY);
250 glVertexPointer(3, GL_FLOAT, 0, vertices);
251 glNormalPointer(GL_FLOAT, 0, normals);
252 if (vertIdxs == NULL)
253 glDrawArrays(GL_TRIANGLES, 0, numVertices);
256 for (i=0; i<numParts; i++)
257 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
259 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
261 glDisableClientState(GL_VERTEX_ARRAY);
262 glDisableClientState(GL_NORMAL_ARRAY);
266 /* Version for OpenGL (ES) >= 2.0 */
267 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLushort *vertIdxs,
268 GLsizei numVertices, GLsizei numParts, GLsizei numVertIdxsPerPart,
269 GLint attribute_v_coord, GLint attribute_v_normal)
271 GLuint vbo_coords = 0, vbo_normals = 0, ibo_elements = 0;
272 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
275 if (numVertices > 0 && attribute_v_coord != -1) {
276 fghGenBuffers(1, &vbo_coords);
277 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
278 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
279 vertices, FGH_STATIC_DRAW);
280 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
283 if (numVertices > 0 && attribute_v_normal != -1) {
284 fghGenBuffers(1, &vbo_normals);
285 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
286 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
287 normals, FGH_STATIC_DRAW);
288 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
291 if (vertIdxs != NULL) {
292 fghGenBuffers(1, &ibo_elements);
293 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
294 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
295 vertIdxs, FGH_STATIC_DRAW);
296 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
300 fghEnableVertexAttribArray(attribute_v_coord);
301 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
302 fghVertexAttribPointer(
303 attribute_v_coord, /* attribute */
304 3, /* number of elements per vertex, here (x,y,z) */
305 GL_FLOAT, /* the type of each element */
306 GL_FALSE, /* take our values as-is */
307 0, /* no extra data between each position */
308 0 /* offset of first element */
310 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
314 fghEnableVertexAttribArray(attribute_v_normal);
315 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
316 fghVertexAttribPointer(
317 attribute_v_normal, /* attribute */
318 3, /* number of elements per vertex, here (x,y,z) */
319 GL_FLOAT, /* the type of each element */
320 GL_FALSE, /* take our values as-is */
321 0, /* no extra data between each position */
322 0 /* offset of first element */
324 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
327 if (vertIdxs == NULL) {
328 glDrawArrays(GL_TRIANGLES, 0, numVertices);
330 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
332 for (i=0; i<numParts; i++) {
333 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
336 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
338 /* Clean existing bindings before clean-up */
339 /* Android showed instability otherwise */
340 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
344 fghDisableVertexAttribArray(attribute_v_coord);
345 if (vbo_normals != 0)
346 fghDisableVertexAttribArray(attribute_v_normal);
349 fghDeleteBuffers(1, &vbo_coords);
350 if (vbo_normals != 0)
351 fghDeleteBuffers(1, &vbo_normals);
352 if (ibo_elements != 0)
353 fghDeleteBuffers(1, &ibo_elements);
356 /* Draw the geometric shape with filled triangles
358 * - If the shape is naturally triangulated (numEdgePerFace==3), each
359 * vertex+normal pair is used only once, so no vertex indices.
361 * - If the shape was triangulated (DECOMPOSE_TO_TRIANGLE), some
362 * vertex+normal pairs are reused, so use vertex indices.
364 static void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLushort *vertIdxs,
365 GLsizei numVertices, GLsizei numParts, GLsizei numVertIdxsPerPart)
367 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
368 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
370 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
371 /* User requested a 2.0 draw */
372 fghDrawGeometrySolid20(vertices, normals, vertIdxs,
373 numVertices, numParts, numVertIdxsPerPart,
374 attribute_v_coord, attribute_v_normal);
375 #ifndef GL_ES_VERSION_2_0
377 fghDrawGeometrySolid11(vertices, normals, vertIdxs,
378 numVertices, numParts, numVertIdxsPerPart);
384 /* Shape decomposition to triangles
385 * We'll use glDrawElements to draw all shapes that are not naturally
386 * composed of triangles, so generate an index vector here, using the
387 * below sampling scheme.
388 * Be careful to keep winding of all triangles counter-clockwise,
389 * assuming that input has correct winding...
391 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
392 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
394 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
396 int i,j,numEdgeIdxPerFace;
397 GLubyte *vertSamps = NULL;
398 switch (numEdgePerFace)
401 /* nothing to do here, we'll draw with glDrawArrays */
404 vertSamps = vert4Decomp;
405 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
408 vertSamps = vert5Decomp;
409 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
413 * Build array with vertices using vertex coordinates and vertex indices
414 * Do same for normals.
415 * Need to do this because of different normals at shared vertices.
417 for (i=0; i<numFaces; i++)
420 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
421 for (j=0; j<numEdgePerFace; j++)
423 int outIdx = i*numEdgePerFace*3+j*3;
424 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
426 vertOut[outIdx ] = vertices[vertIdx ];
427 vertOut[outIdx+1] = vertices[vertIdx+1];
428 vertOut[outIdx+2] = vertices[vertIdx+2];
430 normOut[outIdx ] = normals [normIdx ];
431 normOut[outIdx+1] = normals [normIdx+1];
432 normOut[outIdx+2] = normals [normIdx+2];
435 /* generate vertex indices for each face */
437 for (j=0; j<numEdgeIdxPerFace; j++)
438 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
442 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
444 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
445 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
449 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
450 /* -- stuff that can be cached -- */
451 /* Cache of input to glDrawArrays or glDrawElements
452 * In general, we build arrays with all vertices or normals.
453 * We cant compress this and use glDrawElements as all combinations of
454 * vertices and normals are unique.
456 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
457 static GLboolean name##Cached = FALSE;\
458 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
459 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
460 static void fgh##nameICaps##Generate()\
462 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
463 name##_v, name##_vi, name##_n,\
464 name##_verts, name##_norms);\
466 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
467 static GLboolean name##Cached = FALSE;\
468 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
469 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
470 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
471 static void fgh##nameICaps##Generate()\
473 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
474 name##_v, name##_vi, name##_n,\
475 name##_verts, name##_norms, name##_vertIdxs);\
479 #define CUBE_NUM_VERT 8
480 #define CUBE_NUM_FACES 6
481 #define CUBE_NUM_EDGE_PER_FACE 4
482 #define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
483 #define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
484 #define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
485 /* Vertex Coordinates */
486 static GLfloat cube_v[CUBE_NUM_VERT*3] =
498 static GLfloat cube_n[CUBE_NUM_FACES*3] =
508 /* Vertex indices, as quads, before triangulation */
509 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
518 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
520 /* -- Dodecahedron -- */
521 /* Magic Numbers: It is possible to create a dodecahedron by attaching two
522 * pentagons to each face of of a cube. The coordinates of the points are:
523 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
524 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
525 * x = 0.61803398875 and z = 1.61803398875.
527 #define DODECAHEDRON_NUM_VERT 20
528 #define DODECAHEDRON_NUM_FACES 12
529 #define DODECAHEDRON_NUM_EDGE_PER_FACE 5
530 #define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
531 #define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
532 #define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
533 /* Vertex Coordinates */
534 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
536 0.0f, 1.61803398875f, 0.61803398875f,
538 -0.61803398875f, 0.0f, 1.61803398875f,
539 0.61803398875f, 0.0f, 1.61803398875f,
541 0.0f, 1.61803398875f, -0.61803398875f,
543 0.61803398875f, 0.0f, -1.61803398875f,
544 -0.61803398875f, 0.0f, -1.61803398875f,
545 - 1.0f, 1.0f, - 1.0f,
546 0.0f, -1.61803398875f, 0.61803398875f,
548 - 1.0f, - 1.0f, 1.0f,
549 0.0f, -1.61803398875f, -0.61803398875f,
550 - 1.0f, - 1.0f, - 1.0f,
551 1.0f, - 1.0f, - 1.0f,
552 1.61803398875f, -0.61803398875f, 0.0f,
553 1.61803398875f, 0.61803398875f, 0.0f,
554 -1.61803398875f, 0.61803398875f, 0.0f,
555 -1.61803398875f, -0.61803398875f, 0.0f
558 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
560 0.0f, 0.525731112119f, 0.850650808354f,
561 0.0f, 0.525731112119f, -0.850650808354f,
562 0.0f, -0.525731112119f, 0.850650808354f,
563 0.0f, -0.525731112119f, -0.850650808354f,
565 0.850650808354f, 0.0f, 0.525731112119f,
566 -0.850650808354f, 0.0f, 0.525731112119f,
567 0.850650808354f, 0.0f, -0.525731112119f,
568 -0.850650808354f, 0.0f, -0.525731112119f,
570 0.525731112119f, 0.850650808354f, 0.0f,
571 0.525731112119f, -0.850650808354f, 0.0f,
572 -0.525731112119f, 0.850650808354f, 0.0f,
573 -0.525731112119f, -0.850650808354f, 0.0f,
577 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
594 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
597 /* -- Icosahedron -- */
598 #define ICOSAHEDRON_NUM_VERT 12
599 #define ICOSAHEDRON_NUM_FACES 20
600 #define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
601 #define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
602 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
603 #define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
604 /* Vertex Coordinates */
605 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
608 0.447213595500f, 0.894427191000f, 0.0f,
609 0.447213595500f, 0.276393202252f, 0.850650808354f,
610 0.447213595500f, -0.723606797748f, 0.525731112119f,
611 0.447213595500f, -0.723606797748f, -0.525731112119f,
612 0.447213595500f, 0.276393202252f, -0.850650808354f,
613 -0.447213595500f, -0.894427191000f, 0.0f,
614 -0.447213595500f, -0.276393202252f, 0.850650808354f,
615 -0.447213595500f, 0.723606797748f, 0.525731112119f,
616 -0.447213595500f, 0.723606797748f, -0.525731112119f,
617 -0.447213595500f, -0.276393202252f, -0.850650808354f,
621 * 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] ) ;
622 * 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] ) ;
623 * 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] ) ;
625 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
627 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
628 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
629 0.760845213033849f, -0.581234022404097f, 0.0f,
630 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
631 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
632 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
633 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
634 0.179611190633958f, -0.940456403667806f, 0.0f,
635 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
636 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
637 -0.179611190633958f, 0.940456403667806f, 0.0f,
638 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
639 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
640 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
641 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
642 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
643 -0.760845213033849f, 0.581234022404097f, 0.0f,
644 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
645 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
646 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
650 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
673 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
675 /* -- Octahedron -- */
676 #define OCTAHEDRON_NUM_VERT 6
677 #define OCTAHEDRON_NUM_FACES 8
678 #define OCTAHEDRON_NUM_EDGE_PER_FACE 3
679 #define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
680 #define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
681 #define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
683 /* Vertex Coordinates */
684 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
695 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
697 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
698 0.577350269189f, 0.577350269189f,-0.577350269189f,
699 0.577350269189f,-0.577350269189f, 0.577350269189f,
700 0.577350269189f,-0.577350269189f,-0.577350269189f,
701 -0.577350269189f, 0.577350269189f, 0.577350269189f,
702 -0.577350269189f, 0.577350269189f,-0.577350269189f,
703 -0.577350269189f,-0.577350269189f, 0.577350269189f,
704 -0.577350269189f,-0.577350269189f,-0.577350269189f
709 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
720 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
722 /* -- RhombicDodecahedron -- */
723 #define RHOMBICDODECAHEDRON_NUM_VERT 14
724 #define RHOMBICDODECAHEDRON_NUM_FACES 12
725 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
726 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
727 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
728 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
730 /* Vertex Coordinates */
731 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
734 0.707106781187f, 0.0f, 0.5f,
735 0.0f, 0.707106781187f, 0.5f,
736 -0.707106781187f, 0.0f, 0.5f,
737 0.0f, -0.707106781187f, 0.5f,
738 0.707106781187f, 0.707106781187f, 0.0f,
739 -0.707106781187f, 0.707106781187f, 0.0f,
740 -0.707106781187f, -0.707106781187f, 0.0f,
741 0.707106781187f, -0.707106781187f, 0.0f,
742 0.707106781187f, 0.0f, -0.5f,
743 0.0f, 0.707106781187f, -0.5f,
744 -0.707106781187f, 0.0f, -0.5f,
745 0.0f, -0.707106781187f, -0.5f,
749 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
751 0.353553390594f, 0.353553390594f, 0.5f,
752 -0.353553390594f, 0.353553390594f, 0.5f,
753 -0.353553390594f, -0.353553390594f, 0.5f,
754 0.353553390594f, -0.353553390594f, 0.5f,
759 0.353553390594f, 0.353553390594f, -0.5f,
760 -0.353553390594f, 0.353553390594f, -0.5f,
761 -0.353553390594f, -0.353553390594f, -0.5f,
762 0.353553390594f, -0.353553390594f, -0.5f
766 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
781 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
783 /* -- Tetrahedron -- */
784 /* Magic Numbers: r0 = ( 1, 0, 0 )
785 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
786 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
787 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
788 * |r0| = |r1| = |r2| = |r3| = 1
789 * Distance between any two points is 2 sqrt(6) / 3
791 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
793 #define TETRAHEDRON_NUM_VERT 4
794 #define TETRAHEDRON_NUM_FACES 4
795 #define TETRAHEDRON_NUM_EDGE_PER_FACE 3
796 #define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
797 #define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
798 #define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
800 /* Vertex Coordinates */
801 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
804 -0.333333333333f, 0.942809041582f, 0.0f,
805 -0.333333333333f, -0.471404520791f, 0.816496580928f,
806 -0.333333333333f, -0.471404520791f, -0.816496580928f
809 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
812 0.333333333333f, -0.942809041582f, 0.0f,
813 0.333333333333f, 0.471404520791f, -0.816496580928f,
814 0.333333333333f, 0.471404520791f, 0.816496580928f
818 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
825 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
827 /* -- Sierpinski Sponge -- */
828 static unsigned int ipow (int x, unsigned int y)
830 return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2);
833 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
836 if ( numLevels == 0 )
838 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
841 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
842 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
844 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
845 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
847 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
848 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
849 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
851 normals [outIdx ] = tetrahedron_n[normIdx ];
852 normals [outIdx+1] = tetrahedron_n[normIdx+1];
853 normals [outIdx+2] = tetrahedron_n[normIdx+2];
857 else if ( numLevels > 0 )
859 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
860 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
862 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
865 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
866 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
867 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
868 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
873 /* -- Now the various shapes involving circles -- */
875 * Compute lookup table of cos and sin values forming a circle
876 * (or half circle if halfCircle==TRUE)
879 * It is the responsibility of the caller to free these tables
880 * The size of the table is (n+1) to form a connected loop
881 * The last entry is exactly the same as the first
882 * The sign of n can be flipped to get the reverse loop
884 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
888 /* Table size, the sign of n flips the circle direction */
889 const int size = abs(n);
891 /* Determine the angle between samples */
892 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
894 /* Allocate memory for n samples, plus duplicate of first entry at the end */
895 *sint = malloc(sizeof(GLfloat) * (size+1));
896 *cost = malloc(sizeof(GLfloat) * (size+1));
898 /* Bail out if memory allocation fails, fgError never returns */
899 if (!(*sint) || !(*cost))
903 fgError("Failed to allocate memory in fghCircleTable");
906 /* Compute cos and sin around the circle */
910 for (i=1; i<size; i++)
912 (*sint)[i] = sinf(angle*i);
913 (*cost)[i] = cosf(angle*i);
919 (*sint)[size] = 0.0f; /* sin PI */
920 (*cost)[size] = -1.0f; /* cos PI */
924 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
925 (*sint)[size] = (*sint)[0];
926 (*cost)[size] = (*cost)[0];
930 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
933 int idx = 0; /* idx into vertex/normal buffer */
936 /* Pre-computed circle */
937 GLfloat *sint1,*cost1;
938 GLfloat *sint2,*cost2;
940 /* number of unique vertices */
941 if (slices==0 || stacks<2)
943 /* nothing to generate */
947 *nVert = slices*(stacks-1)+2;
948 if ((*nVert) > 65535) /* TODO: must have a better solution than this low limit, at least for architectures where gluint is available */
949 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
951 /* precompute values on unit circle */
952 fghCircleTable(&sint1,&cost1,-slices,FALSE);
953 fghCircleTable(&sint2,&cost2, stacks,TRUE);
955 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
956 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
957 *normals = malloc((*nVert)*3*sizeof(GLfloat));
958 if (!(*vertices) || !(*normals))
962 fgError("Failed to allocate memory in fghGenerateSphere");
966 (*vertices)[0] = 0.f;
967 (*vertices)[1] = 0.f;
968 (*vertices)[2] = radius;
969 (*normals )[0] = 0.f;
970 (*normals )[1] = 0.f;
971 (*normals )[2] = 1.f;
975 for( i=1; i<stacks; i++ )
977 for(j=0; j<slices; j++, idx+=3)
979 x = cost1[j]*sint2[i];
980 y = sint1[j]*sint2[i];
983 (*vertices)[idx ] = x*radius;
984 (*vertices)[idx+1] = y*radius;
985 (*vertices)[idx+2] = z*radius;
986 (*normals )[idx ] = x;
987 (*normals )[idx+1] = y;
988 (*normals )[idx+2] = z;
993 (*vertices)[idx ] = 0.f;
994 (*vertices)[idx+1] = 0.f;
995 (*vertices)[idx+2] = -radius;
996 (*normals )[idx ] = 0.f;
997 (*normals )[idx+1] = 0.f;
998 (*normals )[idx+2] = -1.f;
1000 /* Done creating vertices, release sin and cos tables */
1007 void fghGenerateCone(
1008 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1009 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1013 int idx = 0; /* idx into vertex/normal buffer */
1015 /* Pre-computed circle */
1016 GLfloat *sint,*cost;
1018 /* Step in z and radius as stacks are drawn. */
1020 GLfloat r = (GLfloat)base;
1022 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1023 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1025 /* Scaling factors for vertex normals */
1026 const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
1027 const GLfloat sinn = ( (GLfloat)base / sqrtf( height * height + base * base ));
1031 /* number of unique vertices */
1032 if (slices==0 || stacks<1)
1034 /* nothing to generate */
1038 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1040 if ((*nVert) > 65535)
1041 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1043 /* Pre-computed circle */
1044 fghCircleTable(&sint,&cost,-slices,FALSE);
1046 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1047 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1048 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1049 if (!(*vertices) || !(*normals))
1053 fgError("Failed to allocate memory in fghGenerateSphere");
1057 (*vertices)[0] = 0.f;
1058 (*vertices)[1] = 0.f;
1060 (*normals )[0] = 0.f;
1061 (*normals )[1] = 0.f;
1062 (*normals )[2] = -1.f;
1064 /* other on bottom (get normals right) */
1065 for (j=0; j<slices; j++, idx+=3)
1067 (*vertices)[idx ] = cost[j]*r;
1068 (*vertices)[idx+1] = sint[j]*r;
1069 (*vertices)[idx+2] = z;
1070 (*normals )[idx ] = 0.f;
1071 (*normals )[idx+1] = 0.f;
1072 (*normals )[idx+2] = -1.f;
1076 for (i=0; i<stacks+1; i++ )
1078 for (j=0; j<slices; j++, idx+=3)
1080 (*vertices)[idx ] = cost[j]*r;
1081 (*vertices)[idx+1] = sint[j]*r;
1082 (*vertices)[idx+2] = z;
1083 (*normals )[idx ] = cost[j]*sinn;
1084 (*normals )[idx+1] = sint[j]*sinn;
1085 (*normals )[idx+2] = cosn;
1092 /* Release sin and cos tables */
1097 void fghGenerateCylinder(
1098 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1099 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1103 int idx = 0; /* idx into vertex/normal buffer */
1105 /* Step in z as stacks are drawn. */
1106 GLfloat radf = (GLfloat)radius;
1108 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1110 /* Pre-computed circle */
1111 GLfloat *sint,*cost;
1113 /* number of unique vertices */
1114 if (slices==0 || stacks<1)
1116 /* nothing to generate */
1120 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1122 if ((*nVert) > 65535)
1123 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1125 /* Pre-computed circle */
1126 fghCircleTable(&sint,&cost,-slices,FALSE);
1128 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1129 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1130 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1131 if (!(*vertices) || !(*normals))
1135 fgError("Failed to allocate memory in fghGenerateCylinder");
1140 (*vertices)[0] = 0.f;
1141 (*vertices)[1] = 0.f;
1142 (*vertices)[2] = 0.f;
1143 (*normals )[0] = 0.f;
1144 (*normals )[1] = 0.f;
1145 (*normals )[2] = -1.f;
1147 /* other on top (get normals right) */
1148 for (j=0; j<slices; j++, idx+=3)
1150 (*vertices)[idx ] = cost[j]*radf;
1151 (*vertices)[idx+1] = sint[j]*radf;
1152 (*vertices)[idx+2] = z;
1153 (*normals )[idx ] = 0.f;
1154 (*normals )[idx+1] = 0.f;
1155 (*normals )[idx+2] = -1.f;
1159 for (i=0; i<stacks+1; i++ )
1161 for (j=0; j<slices; j++, idx+=3)
1163 (*vertices)[idx ] = cost[j]*radf;
1164 (*vertices)[idx+1] = sint[j]*radf;
1165 (*vertices)[idx+2] = z;
1166 (*normals )[idx ] = cost[j];
1167 (*normals )[idx+1] = sint[j];
1168 (*normals )[idx+2] = 0.f;
1174 /* other on bottom (get normals right) */
1176 for (j=0; j<slices; j++, idx+=3)
1178 (*vertices)[idx ] = cost[j]*radf;
1179 (*vertices)[idx+1] = sint[j]*radf;
1180 (*vertices)[idx+2] = z;
1181 (*normals )[idx ] = 0.f;
1182 (*normals )[idx+1] = 0.f;
1183 (*normals )[idx+2] = 1.f;
1187 (*vertices)[idx ] = 0.f;
1188 (*vertices)[idx+1] = 0.f;
1189 (*vertices)[idx+2] = height;
1190 (*normals )[idx ] = 0.f;
1191 (*normals )[idx+1] = 0.f;
1192 (*normals )[idx+2] = 1.f;
1194 /* Release sin and cos tables */
1199 void fghGenerateTorus(
1200 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1201 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1204 GLfloat iradius = (float)dInnerRadius;
1205 GLfloat oradius = (float)dOuterRadius;
1208 /* Pre-computed circle */
1209 GLfloat *spsi, *cpsi;
1210 GLfloat *sphi, *cphi;
1212 /* number of unique vertices */
1213 if (nSides<2 || nRings<2)
1215 /* nothing to generate */
1219 *nVert = nSides * nRings;
1221 if ((*nVert) > 65535)
1222 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1224 /* precompute values on unit circle */
1225 fghCircleTable(&spsi,&cpsi, nRings,FALSE);
1226 fghCircleTable(&sphi,&cphi,-nSides,FALSE);
1228 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1229 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1230 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1231 if (!(*vertices) || !(*normals))
1235 fgError("Failed to allocate memory in fghGenerateTorus");
1238 for( j=0; j<nRings; j++ )
1240 for( i=0; i<nSides; i++ )
1242 int offset = 3 * ( j * nSides + i ) ;
1244 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1245 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1246 (*vertices)[offset+2] = sphi[i] * iradius ;
1247 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1248 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1249 (*normals )[offset+2] = sphi[i] ;
1253 /* Release sin and cos tables */
1260 /* -- INTERNAL DRAWING functions --------------------------------------- */
1261 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1262 static void fgh##nameICaps( GLboolean useWireMode )\
1266 fgh##nameICaps##Generate();\
1267 name##Cached = GL_TRUE;\
1272 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1273 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1278 fghDrawGeometrySolid(name##_verts,name##_norms,vertIdxs,\
1279 nameCaps##_VERT_PER_OBJ, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1282 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1283 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1285 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1292 cubeCached = GL_TRUE;
1297 /* Need to build new vertex list containing vertices for cube of different size */
1300 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1302 /* Bail out if memory allocation fails, fgError never returns */
1306 fgError("Failed to allocate memory in fghCube");
1309 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1310 vertices[i] = dSize*cube_verts[i];
1313 vertices = cube_verts;
1316 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1317 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1320 fghDrawGeometrySolid(vertices, cube_norms, cube_vertIdxs,
1321 CUBE_VERT_PER_OBJ, 1, CUBE_VERT_PER_OBJ_TRI);
1324 /* cleanup allocated memory */
1328 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1329 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1330 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1331 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1332 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1334 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1338 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1339 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1340 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1344 /* Allocate memory */
1345 vertices = malloc(numVert*3 * sizeof(GLfloat));
1346 normals = malloc(numVert*3 * sizeof(GLfloat));
1347 /* Bail out if memory allocation fails, fgError never returns */
1348 if (!vertices || !normals)
1352 fgError("Failed to allocate memory in fghSierpinskiSponge");
1355 /* Generate elements */
1356 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1358 /* Draw and cleanup */
1360 fghDrawGeometryWire (vertices,normals,numVert,
1361 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1364 fghDrawGeometrySolid(vertices,normals,NULL,numVert,1,0);
1372 static void fghSphere( double radius, GLint slices, GLint stacks, GLboolean useWireMode )
1375 GLfloat *vertices, *normals;
1377 /* Generate vertices and normals */
1378 fghGenerateSphere((GLfloat)radius,slices,stacks,&vertices,&normals,&nVert);
1381 /* nothing to draw */
1386 GLushort *sliceIdx, *stackIdx;
1387 /* First, generate vertex index arrays for drawing with glDrawElements
1388 * We have a bunch of line_loops to draw for each stack, and a
1389 * bunch for each slice.
1392 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1393 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1394 if (!(stackIdx) || !(sliceIdx))
1398 fgError("Failed to allocate memory in fghSphere");
1401 /* generate for each stack */
1402 for (i=0,idx=0; i<stacks-1; i++)
1404 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1405 for (j=0; j<slices; j++, idx++)
1407 stackIdx[idx] = offset+j;
1411 /* generate for each slice */
1412 for (i=0,idx=0; i<slices; i++)
1414 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1415 sliceIdx[idx++] = 0; /* vertex on top */
1416 for (j=0; j<stacks-1; j++, idx++)
1418 sliceIdx[idx] = offset+j*slices;
1420 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1424 fghDrawGeometryWire(vertices,normals,nVert,
1425 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1426 stackIdx,stacks-1,slices);
1428 /* cleanup allocated memory */
1434 /* First, generate vertex index arrays for drawing with glDrawElements
1435 * All stacks, including top and bottom are covered with a triangle
1439 /* Create index vector */
1442 /* Allocate buffers for indices, bail out if memory allocation fails */
1443 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1447 fgError("Failed to allocate memory in fghSphere");
1451 for (j=0, idx=0; j<slices; j++, idx+=2)
1453 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1454 stripIdx[idx+1] = 0;
1456 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1457 stripIdx[idx+1] = 0;
1460 /* middle stacks: */
1461 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1462 for (i=0; i<stacks-2; i++, idx+=2)
1464 offset = 1+i*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1465 for (j=0; j<slices; j++, idx+=2)
1467 stripIdx[idx ] = offset+j+slices;
1468 stripIdx[idx+1] = offset+j;
1470 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1471 stripIdx[idx+1] = offset;
1475 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 */
1476 for (j=0; j<slices; j++, idx+=2)
1478 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1479 stripIdx[idx+1] = offset+j;
1481 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1482 stripIdx[idx+1] = offset;
1486 fghDrawGeometrySolid(vertices,normals,stripIdx,nVert,stacks,(slices+1)*2);
1488 /* cleanup allocated memory */
1492 /* cleanup allocated memory */
1497 static void fghCone( double base, double height, GLint slices, GLint stacks, GLboolean useWireMode )
1500 GLfloat *vertices, *normals;
1502 /* Generate vertices and normals */
1503 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1504 fghGenerateCone((GLfloat)base,(GLfloat)height,slices,stacks,&vertices,&normals,&nVert);
1507 /* nothing to draw */
1512 GLushort *sliceIdx, *stackIdx;
1513 /* First, generate vertex index arrays for drawing with glDrawElements
1514 * We have a bunch of line_loops to draw for each stack, and a
1515 * bunch for each slice.
1518 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1519 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1520 if (!(stackIdx) || !(sliceIdx))
1524 fgError("Failed to allocate memory in fghCone");
1527 /* generate for each stack */
1528 for (i=0,idx=0; i<stacks; i++)
1530 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1531 for (j=0; j<slices; j++, idx++)
1533 stackIdx[idx] = offset+j;
1537 /* generate for each slice */
1538 for (i=0,idx=0; i<slices; i++)
1540 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1541 sliceIdx[idx++] = offset+slices;
1542 sliceIdx[idx++] = offset+(stacks+1)*slices;
1546 fghDrawGeometryWire(vertices,normals,nVert,
1547 sliceIdx,1,slices*2,GL_LINES,
1548 stackIdx,stacks,slices);
1550 /* cleanup allocated memory */
1556 /* First, generate vertex index arrays for drawing with glDrawElements
1557 * All stacks, including top and bottom are covered with a triangle
1561 /* Create index vector */
1564 /* Allocate buffers for indices, bail out if memory allocation fails */
1565 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1569 fgError("Failed to allocate memory in fghCone");
1573 for (j=0, idx=0; j<slices; j++, idx+=2)
1576 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1578 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1579 stripIdx[idx+1] = 1;
1582 /* middle stacks: */
1583 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1584 for (i=0; i<stacks; i++, idx+=2)
1586 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 */
1587 for (j=0; j<slices; j++, idx+=2)
1589 stripIdx[idx ] = offset+j;
1590 stripIdx[idx+1] = offset+j+slices;
1592 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1593 stripIdx[idx+1] = offset+slices;
1597 fghDrawGeometrySolid(vertices,normals,stripIdx,nVert,stacks+1,(slices+1)*2);
1599 /* cleanup allocated memory */
1603 /* cleanup allocated memory */
1608 static void fghCylinder( double radius, double height, GLint slices, GLint stacks, GLboolean useWireMode )
1611 GLfloat *vertices, *normals;
1613 /* Generate vertices and normals */
1614 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1615 fghGenerateCylinder((GLfloat)radius,(GLfloat)height,slices,stacks,&vertices,&normals,&nVert);
1618 /* nothing to draw */
1623 GLushort *sliceIdx, *stackIdx;
1624 /* First, generate vertex index arrays for drawing with glDrawElements
1625 * We have a bunch of line_loops to draw for each stack, and a
1626 * bunch for each slice.
1629 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1630 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1631 if (!(stackIdx) || !(sliceIdx))
1635 fgError("Failed to allocate memory in fghCylinder");
1638 /* generate for each stack */
1639 for (i=0,idx=0; i<stacks+1; i++)
1641 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1642 for (j=0; j<slices; j++, idx++)
1644 stackIdx[idx] = offset+j;
1648 /* generate for each slice */
1649 for (i=0,idx=0; i<slices; i++)
1651 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1652 sliceIdx[idx++] = offset+slices;
1653 sliceIdx[idx++] = offset+(stacks+1)*slices;
1657 fghDrawGeometryWire(vertices,normals,nVert,
1658 sliceIdx,1,slices*2,GL_LINES,
1659 stackIdx,stacks+1,slices);
1661 /* cleanup allocated memory */
1667 /* First, generate vertex index arrays for drawing with glDrawElements
1668 * All stacks, including top and bottom are covered with a triangle
1672 /* Create index vector */
1675 /* Allocate buffers for indices, bail out if memory allocation fails */
1676 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1680 fgError("Failed to allocate memory in fghCylinder");
1684 for (j=0, idx=0; j<slices; j++, idx+=2)
1687 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1689 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1690 stripIdx[idx+1] = 1;
1693 /* middle stacks: */
1694 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1695 for (i=0; i<stacks; i++, idx+=2)
1697 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 */
1698 for (j=0; j<slices; j++, idx+=2)
1700 stripIdx[idx ] = offset+j;
1701 stripIdx[idx+1] = offset+j+slices;
1703 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1704 stripIdx[idx+1] = offset+slices;
1708 offset = 1+(stacks+2)*slices;
1709 for (j=0; j<slices; j++, idx+=2)
1711 stripIdx[idx ] = offset+j;
1712 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1714 stripIdx[idx ] = offset;
1715 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1718 fghDrawGeometrySolid(vertices,normals,stripIdx,nVert,stacks+2,(slices+1)*2);
1720 /* cleanup allocated memory */
1724 /* cleanup allocated memory */
1729 static void fghTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1732 GLfloat *vertices, *normals;
1734 /* Generate vertices and normals */
1735 fghGenerateTorus((GLfloat)dInnerRadius,(GLfloat)dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1738 /* nothing to draw */
1743 GLushort *sideIdx, *ringIdx;
1744 /* First, generate vertex index arrays for drawing with glDrawElements
1745 * We have a bunch of line_loops to draw each side, and a
1746 * bunch for each ring.
1749 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1750 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1751 if (!(ringIdx) || !(sideIdx))
1755 fgError("Failed to allocate memory in fghTorus");
1758 /* generate for each ring */
1759 for( j=0,idx=0; j<nRings; j++ )
1760 for( i=0; i<nSides; i++, idx++ )
1761 ringIdx[idx] = j * nSides + i;
1763 /* generate for each side */
1764 for( i=0,idx=0; i<nSides; i++ )
1765 for( j=0; j<nRings; j++, idx++ )
1766 sideIdx[idx] = j * nSides + i;
1769 fghDrawGeometryWire(vertices,normals,nVert,
1770 ringIdx,nRings,nSides,GL_LINE_LOOP,
1771 sideIdx,nSides,nRings);
1773 /* cleanup allocated memory */
1779 /* First, generate vertex index arrays for drawing with glDrawElements
1780 * All stacks, including top and bottom are covered with a triangle
1785 /* Allocate buffers for indices, bail out if memory allocation fails */
1786 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
1790 fgError("Failed to allocate memory in fghTorus");
1793 for( i=0, idx=0; i<nSides; i++ )
1799 for( j=0; j<nRings; j++, idx+=2 )
1801 int offset = j * nSides + i;
1802 stripIdx[idx ] = offset;
1803 stripIdx[idx+1] = offset + ioff;
1805 /* repeat first to close off shape */
1807 stripIdx[idx+1] = i + ioff;
1812 fghDrawGeometrySolid(vertices,normals,stripIdx,nVert,nSides,(nRings+1)*2);
1814 /* cleanup allocated memory */
1818 /* cleanup allocated memory */
1824 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
1828 * Draws a solid sphere
1830 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
1832 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
1834 fghSphere( radius, slices, stacks, FALSE );
1838 * Draws a wire sphere
1840 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
1842 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
1844 fghSphere( radius, slices, stacks, TRUE );
1849 * Draws a solid cone
1851 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
1853 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
1855 fghCone( base, height, slices, stacks, FALSE );
1861 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
1863 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
1865 fghCone( base, height, slices, stacks, TRUE );
1870 * Draws a solid cylinder
1872 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
1874 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
1876 fghCylinder( radius, height, slices, stacks, FALSE );
1880 * Draws a wire cylinder
1882 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
1884 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
1886 fghCylinder( radius, height, slices, stacks, TRUE );
1890 * Draws a wire torus
1892 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1894 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
1896 fghTorus(dInnerRadius, dOuterRadius, nSides, nRings, TRUE);
1900 * Draws a solid torus
1902 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
1904 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
1906 fghTorus(dInnerRadius, dOuterRadius, nSides, nRings, FALSE);
1911 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1912 /* Macro to generate interface functions */
1913 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
1914 void FGAPIENTRY glutWire##nameICaps( void )\
1916 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
1917 fgh##nameICaps( TRUE );\
1919 void FGAPIENTRY glutSolid##nameICaps( void )\
1921 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
1922 fgh##nameICaps( FALSE );\
1925 void FGAPIENTRY glutWireCube( double dSize )
1927 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
1928 fghCube( (GLfloat)dSize, TRUE );
1930 void FGAPIENTRY glutSolidCube( double dSize )
1932 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
1933 fghCube( (GLfloat)dSize, FALSE );
1936 DECLARE_SHAPE_INTERFACE(Dodecahedron)
1937 DECLARE_SHAPE_INTERFACE(Icosahedron)
1938 DECLARE_SHAPE_INTERFACE(Octahedron)
1939 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
1941 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
1943 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
1944 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
1946 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
1948 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
1949 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
1952 DECLARE_SHAPE_INTERFACE(Tetrahedron)
1955 /*** END OF FILE ***/