4 * Freeglut geometry rendering methods.
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Creation date: Fri Dec 3 1999
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <GL/freeglut.h>
29 #include "fg_internal.h"
33 /* declare for drawing using the different OpenGL versions here so we can
34 have a nice code order below */
35 #ifndef GL_ES_VERSION_2_0
36 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
37 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
38 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
40 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
41 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
43 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
44 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
45 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
46 GLint attribute_v_coord, GLint attribute_v_normal
48 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
49 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
50 GLint attribute_v_coord, GLint attribute_v_normal);
51 /* declare function for generating visualization of normals */
52 static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
53 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
54 static void fghDrawNormalVisualization();
57 * Explanation of the functions has to be separate for the polyhedra and
58 * the non-polyhedra (objects with a circular cross-section).
60 * - We have only implemented the five platonic solids and the rhomboid
61 * dodecahedron. If you need more types of polyhedra, please see
63 * - Solids are drawn by glDrawArrays if composed of triangular faces
64 * (the tetrahedron, octahedron, and icosahedron), or are first
65 * decomposed into triangles and then drawn by glDrawElements if its
66 * faces are squares or pentagons (cube, dodecahedron and rhombic
67 * dodecahedron) as some vertices are repeated in that case.
68 * - WireFrame drawing is done using a GL_LINE_LOOP per face, and thus
69 * issuing one draw call per face. glDrawArrays is always used as no
70 * triangle decomposition is needed to draw faces. We use the "first"
71 * parameter in glDrawArrays to go from face to face.
74 * - We have implemented the sphere, cylinder, cone and torus.
75 * - All shapes are characterized by two parameters: the number of
76 * subdivisions along two axes used to construct the shape's vertices
77 * (e.g. stacks and slices for the sphere).
78 * As different subdivisions are most suitable for different shapes,
79 * and are thus also named differently, I wont provide general comments
81 * - Solids are drawn using glDrawArrays and GL_TRIANGLE_STRIP. Each
82 * strip covers one revolution around one of the two subdivision axes
84 * - WireFrame drawing is done for the subdivisions along the two axes
85 * separately, usually using GL_LINE_LOOP. Vertex index arrays are
86 * built containing the vertices to be drawn for each loop, which are
87 * then drawn using multiple calls to glDrawElements. As the number of
88 * subdivisions along the two axes is not guaranteed to be equal, the
89 * vertex indices for e.g. stacks and slices are stored in separate
90 * arrays, which makes the input to the drawing function a bit clunky,
91 * but allows for the same drawing function to be used for all shapes.
96 * Draw geometric shape in wire mode (only edges)
99 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
100 * The vertex coordinate and normal buffers, and the number of entries in
103 * a vertex indices buffer, optional (never passed for the polyhedra)
104 * GLsizei numParts, GLsizei numVertPerPart
105 * polyhedra: number of faces, and the number of vertices for drawing
107 * non-polyhedra: number of edges to draw for first subdivision (not
108 * necessarily equal to number of subdivisions requested by user, e.g.
109 * as each subdivision is enclosed by two edges), and number of
110 * vertices for drawing each
111 * numParts * numVertPerPart gives the number of entries in the vertex
114 * vertex drawing mode (e.g. always GL_LINE_LOOP for polyhedra, varies
116 * GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
117 * non-polyhedra only: same as the above, but now for subdivisions along
118 * the other axis. Always drawn as GL_LINE_LOOP.
120 * Feel free to contribute better naming ;)
122 static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
123 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
124 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
127 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
128 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
130 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
131 /* User requested a 2.0 draw */
132 fghDrawGeometryWire20(vertices, normals, numVertices,
133 vertIdxs, numParts, numVertPerPart, vertexMode,
134 vertIdxs2, numParts2, numVertPerPart2,
135 attribute_v_coord, attribute_v_normal);
136 #ifndef GL_ES_VERSION_2_0
138 fghDrawGeometryWire11(vertices, normals,
139 vertIdxs, numParts, numVertPerPart, vertexMode,
140 vertIdxs2, numParts2, numVertPerPart2);
144 /* Draw the geometric shape with filled triangles
147 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
148 * The vertex coordinate and normal buffers, and the number of entries in
151 * a vertex indices buffer, optional (not passed for the polyhedra with
153 * GLsizei numParts, GLsizei numVertPerPart
154 * polyhedra: not used for polyhedra with triangular faces
155 (numEdgePerFace==3), as each vertex+normal pair is drawn only once,
156 so no vertex indices are used.
157 Else, the shape was triangulated (DECOMPOSE_TO_TRIANGLE), leading to
158 reuse of some vertex+normal pairs, and thus the need to draw with
159 glDrawElements. numParts is always 1 in this case (we can draw the
160 whole object with one call to glDrawElements as the vertex index
161 array contains separate triangles), and numVertPerPart indicates
162 the number of vertex indices in the vertex array.
163 * non-polyhedra: number of parts (GL_TRIANGLE_STRIPs) to be drawn
164 separately (numParts calls to glDrawElements) to create the object.
165 numVertPerPart indicates the number of vertex indices to be
166 processed at each draw call.
167 * numParts * numVertPerPart gives the number of entries in the vertex
170 static void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
171 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
173 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
174 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
176 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
177 /* User requested a 2.0 draw */
178 fghDrawGeometrySolid20(vertices, normals, numVertices,
179 vertIdxs, numParts, numVertIdxsPerPart,
180 attribute_v_coord, attribute_v_normal);
181 #ifndef GL_ES_VERSION_2_0
184 fghDrawGeometrySolid11(vertices, normals, numVertices,
185 vertIdxs, numParts, numVertIdxsPerPart);
187 if (fgStructure.CurrentWindow->State.VisualizeNormals)
189 /* generate normals for each vertex to be drawn as well */
190 fghGenerateNormalVisualization(vertices, normals, numVertices,
191 vertIdxs, numParts, numVertIdxsPerPart);
192 /* draw normals for each vertex as well */
193 fghDrawNormalVisualization();
201 /* Version for OpenGL (ES) 1.1 */
202 #ifndef GL_ES_VERSION_2_0
203 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
204 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
205 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
210 glEnableClientState(GL_VERTEX_ARRAY);
211 glEnableClientState(GL_NORMAL_ARRAY);
213 glVertexPointer(3, GL_FLOAT, 0, vertices);
214 glNormalPointer(GL_FLOAT, 0, normals);
218 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
219 for (i=0; i<numParts; i++)
220 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
222 for (i=0; i<numParts; i++)
223 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
226 for (i=0; i<numParts2; i++)
227 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
229 glDisableClientState(GL_VERTEX_ARRAY);
230 glDisableClientState(GL_NORMAL_ARRAY);
234 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
235 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
239 glEnableClientState(GL_VERTEX_ARRAY);
240 glEnableClientState(GL_NORMAL_ARRAY);
242 glVertexPointer(3, GL_FLOAT, 0, vertices);
243 glNormalPointer(GL_FLOAT, 0, normals);
246 glDrawArrays(GL_TRIANGLES, 0, numVertices);
249 for (i=0; i<numParts; i++)
250 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
252 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
254 glDisableClientState(GL_VERTEX_ARRAY);
255 glDisableClientState(GL_NORMAL_ARRAY);
259 /* Version for OpenGL (ES) >= 2.0 */
260 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
261 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
262 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
263 GLint attribute_v_coord, GLint attribute_v_normal)
265 GLuint vbo_coords = 0, vbo_normals = 0,
266 ibo_elements = 0, ibo_elements2 = 0;
267 GLsizei numVertIdxs = numParts * numVertPerPart;
268 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
271 if (numVertices > 0 && attribute_v_coord != -1) {
272 fghGenBuffers(1, &vbo_coords);
273 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
274 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
275 vertices, FGH_STATIC_DRAW);
278 if (numVertices > 0 && attribute_v_normal != -1) {
279 fghGenBuffers(1, &vbo_normals);
280 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
281 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
282 normals, FGH_STATIC_DRAW);
285 if (vertIdxs != NULL) {
286 fghGenBuffers(1, &ibo_elements);
287 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
288 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
289 vertIdxs, FGH_STATIC_DRAW);
290 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
293 if (vertIdxs2 != NULL) {
294 fghGenBuffers(1, &ibo_elements2);
295 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
296 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
297 vertIdxs2, FGH_STATIC_DRAW);
298 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
302 fghEnableVertexAttribArray(attribute_v_coord);
303 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
304 fghVertexAttribPointer(
305 attribute_v_coord, /* attribute */
306 3, /* number of elements per vertex, here (x,y,z) */
307 GL_FLOAT, /* the type of each element */
308 GL_FALSE, /* take our values as-is */
309 0, /* no extra data between each position */
310 0 /* offset of first element */
312 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
316 fghEnableVertexAttribArray(attribute_v_normal);
317 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
318 fghVertexAttribPointer(
319 attribute_v_normal, /* attribute */
320 3, /* number of elements per vertex, here (x,y,z) */
321 GL_FLOAT, /* the type of each element */
322 GL_FALSE, /* take our values as-is */
323 0, /* no extra data between each position */
324 0 /* offset of first element */
326 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
330 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
331 for (i=0; i<numParts; i++)
332 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
334 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
335 for (i=0; i<numParts; i++)
336 glDrawElements(vertexMode, numVertPerPart,
337 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
338 /* Clean existing bindings before clean-up */
339 /* Android showed instability otherwise */
340 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
344 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
345 for (i=0; i<numParts2; i++)
346 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
347 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
348 /* Clean existing bindings before clean-up */
349 /* Android showed instability otherwise */
350 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
354 fghDisableVertexAttribArray(attribute_v_coord);
355 if (vbo_normals != 0)
356 fghDisableVertexAttribArray(attribute_v_normal);
359 fghDeleteBuffers(1, &vbo_coords);
360 if (vbo_normals != 0)
361 fghDeleteBuffers(1, &vbo_normals);
362 if (ibo_elements != 0)
363 fghDeleteBuffers(1, &ibo_elements);
364 if (ibo_elements2 != 0)
365 fghDeleteBuffers(1, &ibo_elements2);
371 /* Version for OpenGL (ES) >= 2.0 */
372 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
373 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
374 GLint attribute_v_coord, GLint attribute_v_normal)
376 GLuint vbo_coords = 0, vbo_normals = 0, ibo_elements = 0;
377 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
380 if (numVertices > 0 && attribute_v_coord != -1) {
381 fghGenBuffers(1, &vbo_coords);
382 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
383 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
384 vertices, FGH_STATIC_DRAW);
385 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
388 if (numVertices > 0 && attribute_v_normal != -1) {
389 fghGenBuffers(1, &vbo_normals);
390 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
391 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
392 normals, FGH_STATIC_DRAW);
393 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
396 if (vertIdxs != NULL) {
397 fghGenBuffers(1, &ibo_elements);
398 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
399 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
400 vertIdxs, FGH_STATIC_DRAW);
401 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
405 fghEnableVertexAttribArray(attribute_v_coord);
406 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
407 fghVertexAttribPointer(
408 attribute_v_coord, /* attribute */
409 3, /* number of elements per vertex, here (x,y,z) */
410 GL_FLOAT, /* the type of each element */
411 GL_FALSE, /* take our values as-is */
412 0, /* no extra data between each position */
413 0 /* offset of first element */
415 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
419 fghEnableVertexAttribArray(attribute_v_normal);
420 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
421 fghVertexAttribPointer(
422 attribute_v_normal, /* attribute */
423 3, /* number of elements per vertex, here (x,y,z) */
424 GL_FLOAT, /* the type of each element */
425 GL_FALSE, /* take our values as-is */
426 0, /* no extra data between each position */
427 0 /* offset of first element */
429 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
432 if (vertIdxs == NULL) {
433 glDrawArrays(GL_TRIANGLES, 0, numVertices);
435 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
437 for (i=0; i<numParts; i++) {
438 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
441 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
443 /* Clean existing bindings before clean-up */
444 /* Android showed instability otherwise */
445 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
449 fghDisableVertexAttribArray(attribute_v_coord);
450 if (vbo_normals != 0)
451 fghDisableVertexAttribArray(attribute_v_normal);
454 fghDeleteBuffers(1, &vbo_coords);
455 if (vbo_normals != 0)
456 fghDeleteBuffers(1, &vbo_normals);
457 if (ibo_elements != 0)
458 fghDeleteBuffers(1, &ibo_elements);
464 * Generate vertex indices for visualizing the normals.
466 static GLfloat *verticesForNormalVisualization;
467 static GLushort numNormalVertices = 0;
468 static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
469 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
472 /* calc number of vertices to generate, allocate. TODO: FREE again after draw!
473 * two for each vertex in the input shape
476 numNormalVertices = numVertices * 2;
478 numNormalVertices = numParts * numVertIdxsPerPart * 2;
479 verticesForNormalVisualization = malloc(numNormalVertices*3 * sizeof(GLfloat));
481 /* Now generate vertices for lines to draw the normals */
484 for (i=0,j=0; i<numNormalVertices*3/2; i+=3, j+=6)
486 verticesForNormalVisualization[j+0] = vertices[i+0];
487 verticesForNormalVisualization[j+1] = vertices[i+1];
488 verticesForNormalVisualization[j+2] = vertices[i+2];
489 verticesForNormalVisualization[j+3] = vertices[i+0] + normals[i+0]/4.f;
490 verticesForNormalVisualization[j+4] = vertices[i+1] + normals[i+1]/4.f;
491 verticesForNormalVisualization[j+5] = vertices[i+2] + normals[i+2]/4.f;
496 for (i=0,j=0; i<numNormalVertices/2; i++, j+=6)
498 GLushort idx = vertIdxs[i]*3;
499 verticesForNormalVisualization[j+0] = vertices[idx+0];
500 verticesForNormalVisualization[j+1] = vertices[idx+1];
501 verticesForNormalVisualization[j+2] = vertices[idx+2];
502 verticesForNormalVisualization[j+3] = vertices[idx+0] + normals[idx+0]/4.f;
503 verticesForNormalVisualization[j+4] = vertices[idx+1] + normals[idx+1]/4.f;
504 verticesForNormalVisualization[j+5] = vertices[idx+2] + normals[idx+2]/4.f;
509 static void fghDrawNormalVisualization()
511 GLfloat currentColor[4];
512 /* Setup draw color: (1,1,1)-shape's color */
513 glGetFloatv(GL_CURRENT_COLOR,currentColor);
514 glColor4f(1-currentColor[0],1-currentColor[1],1-currentColor[2],currentColor[3]);
516 glEnableClientState(GL_VERTEX_ARRAY);
518 glVertexPointer(3, GL_FLOAT, 0, verticesForNormalVisualization);
519 glDrawArrays(GL_LINES, 0, numNormalVertices);
521 glDisableClientState(GL_VERTEX_ARRAY);
523 /* Done, free memory, reset color */
524 free(verticesForNormalVisualization);
525 glColor4fv(currentColor);
529 * Generate all combinations of vertices and normals needed to draw object.
530 * Optional shape decomposition to triangles:
531 * We'll use glDrawElements to draw all shapes that are not naturally
532 * composed of triangles, so generate an index vector here, using the
533 * below sampling scheme.
534 * Be careful to keep winding of all triangles counter-clockwise,
535 * assuming that input has correct winding...
537 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
538 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
540 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
542 int i,j,numEdgeIdxPerFace;
543 GLubyte *vertSamps = NULL;
544 switch (numEdgePerFace)
547 /* nothing to do here, we'll draw with glDrawArrays */
550 vertSamps = vert4Decomp;
551 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
554 vertSamps = vert5Decomp;
555 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
559 * Build array with vertices using vertex coordinates and vertex indices
560 * Do same for normals.
561 * Need to do this because of different normals at shared vertices.
563 for (i=0; i<numFaces; i++)
566 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
567 for (j=0; j<numEdgePerFace; j++)
569 int outIdx = i*numEdgePerFace*3+j*3;
570 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
572 vertOut[outIdx ] = vertices[vertIdx ];
573 vertOut[outIdx+1] = vertices[vertIdx+1];
574 vertOut[outIdx+2] = vertices[vertIdx+2];
576 normOut[outIdx ] = normals [normIdx ];
577 normOut[outIdx+1] = normals [normIdx+1];
578 normOut[outIdx+2] = normals [normIdx+2];
581 /* generate vertex indices for each face */
583 for (j=0; j<numEdgeIdxPerFace; j++)
584 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
588 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
590 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
591 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
595 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
596 /* -- stuff that can be cached -- */
597 /* Cache of input to glDrawArrays or glDrawElements
598 * In general, we build arrays with all vertices or normals.
599 * We cant compress this and use glDrawElements as all combinations of
600 * vertices and normals are unique.
602 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
603 static GLboolean name##Cached = FALSE;\
604 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
605 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
606 static void fgh##nameICaps##Generate()\
608 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
609 name##_v, name##_vi, name##_n,\
610 name##_verts, name##_norms);\
612 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
613 static GLboolean name##Cached = FALSE;\
614 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
615 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
616 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
617 static void fgh##nameICaps##Generate()\
619 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
620 name##_v, name##_vi, name##_n,\
621 name##_verts, name##_norms, name##_vertIdxs);\
625 #define CUBE_NUM_VERT 8
626 #define CUBE_NUM_FACES 6
627 #define CUBE_NUM_EDGE_PER_FACE 4
628 #define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
629 #define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
630 #define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
631 /* Vertex Coordinates */
632 static GLfloat cube_v[CUBE_NUM_VERT*3] =
644 static GLfloat cube_n[CUBE_NUM_FACES*3] =
654 /* Vertex indices, as quads, before triangulation */
655 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
664 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
666 /* -- Dodecahedron -- */
667 /* Magic Numbers: It is possible to create a dodecahedron by attaching two
668 * pentagons to each face of of a cube. The coordinates of the points are:
669 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
670 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
671 * x = 0.61803398875 and z = 1.61803398875.
673 #define DODECAHEDRON_NUM_VERT 20
674 #define DODECAHEDRON_NUM_FACES 12
675 #define DODECAHEDRON_NUM_EDGE_PER_FACE 5
676 #define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
677 #define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
678 #define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
679 /* Vertex Coordinates */
680 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
682 0.0f, 1.61803398875f, 0.61803398875f,
684 -0.61803398875f, 0.0f, 1.61803398875f,
685 0.61803398875f, 0.0f, 1.61803398875f,
687 0.0f, 1.61803398875f, -0.61803398875f,
689 0.61803398875f, 0.0f, -1.61803398875f,
690 -0.61803398875f, 0.0f, -1.61803398875f,
691 - 1.0f, 1.0f, - 1.0f,
692 0.0f, -1.61803398875f, 0.61803398875f,
694 - 1.0f, - 1.0f, 1.0f,
695 0.0f, -1.61803398875f, -0.61803398875f,
696 - 1.0f, - 1.0f, - 1.0f,
697 1.0f, - 1.0f, - 1.0f,
698 1.61803398875f, -0.61803398875f, 0.0f,
699 1.61803398875f, 0.61803398875f, 0.0f,
700 -1.61803398875f, 0.61803398875f, 0.0f,
701 -1.61803398875f, -0.61803398875f, 0.0f
704 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
706 0.0f, 0.525731112119f, 0.850650808354f,
707 0.0f, 0.525731112119f, -0.850650808354f,
708 0.0f, -0.525731112119f, 0.850650808354f,
709 0.0f, -0.525731112119f, -0.850650808354f,
711 0.850650808354f, 0.0f, 0.525731112119f,
712 -0.850650808354f, 0.0f, 0.525731112119f,
713 0.850650808354f, 0.0f, -0.525731112119f,
714 -0.850650808354f, 0.0f, -0.525731112119f,
716 0.525731112119f, 0.850650808354f, 0.0f,
717 0.525731112119f, -0.850650808354f, 0.0f,
718 -0.525731112119f, 0.850650808354f, 0.0f,
719 -0.525731112119f, -0.850650808354f, 0.0f,
723 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
740 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
743 /* -- Icosahedron -- */
744 #define ICOSAHEDRON_NUM_VERT 12
745 #define ICOSAHEDRON_NUM_FACES 20
746 #define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
747 #define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
748 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
749 #define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
750 /* Vertex Coordinates */
751 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
754 0.447213595500f, 0.894427191000f, 0.0f,
755 0.447213595500f, 0.276393202252f, 0.850650808354f,
756 0.447213595500f, -0.723606797748f, 0.525731112119f,
757 0.447213595500f, -0.723606797748f, -0.525731112119f,
758 0.447213595500f, 0.276393202252f, -0.850650808354f,
759 -0.447213595500f, -0.894427191000f, 0.0f,
760 -0.447213595500f, -0.276393202252f, 0.850650808354f,
761 -0.447213595500f, 0.723606797748f, 0.525731112119f,
762 -0.447213595500f, 0.723606797748f, -0.525731112119f,
763 -0.447213595500f, -0.276393202252f, -0.850650808354f,
767 * 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] ) ;
768 * 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] ) ;
769 * 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] ) ;
771 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
773 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
774 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
775 0.760845213033849f, -0.581234022404097f, 0.0f,
776 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
777 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
778 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
779 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
780 0.179611190633958f, -0.940456403667806f, 0.0f,
781 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
782 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
783 -0.179611190633958f, 0.940456403667806f, 0.0f,
784 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
785 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
786 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
787 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
788 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
789 -0.760845213033849f, 0.581234022404097f, 0.0f,
790 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
791 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
792 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
796 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
819 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
821 /* -- Octahedron -- */
822 #define OCTAHEDRON_NUM_VERT 6
823 #define OCTAHEDRON_NUM_FACES 8
824 #define OCTAHEDRON_NUM_EDGE_PER_FACE 3
825 #define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
826 #define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
827 #define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
829 /* Vertex Coordinates */
830 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
841 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
843 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
844 0.577350269189f, 0.577350269189f,-0.577350269189f,
845 0.577350269189f,-0.577350269189f, 0.577350269189f,
846 0.577350269189f,-0.577350269189f,-0.577350269189f,
847 -0.577350269189f, 0.577350269189f, 0.577350269189f,
848 -0.577350269189f, 0.577350269189f,-0.577350269189f,
849 -0.577350269189f,-0.577350269189f, 0.577350269189f,
850 -0.577350269189f,-0.577350269189f,-0.577350269189f
855 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
866 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
868 /* -- RhombicDodecahedron -- */
869 #define RHOMBICDODECAHEDRON_NUM_VERT 14
870 #define RHOMBICDODECAHEDRON_NUM_FACES 12
871 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
872 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
873 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
874 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
876 /* Vertex Coordinates */
877 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
880 0.707106781187f, 0.0f, 0.5f,
881 0.0f, 0.707106781187f, 0.5f,
882 -0.707106781187f, 0.0f, 0.5f,
883 0.0f, -0.707106781187f, 0.5f,
884 0.707106781187f, 0.707106781187f, 0.0f,
885 -0.707106781187f, 0.707106781187f, 0.0f,
886 -0.707106781187f, -0.707106781187f, 0.0f,
887 0.707106781187f, -0.707106781187f, 0.0f,
888 0.707106781187f, 0.0f, -0.5f,
889 0.0f, 0.707106781187f, -0.5f,
890 -0.707106781187f, 0.0f, -0.5f,
891 0.0f, -0.707106781187f, -0.5f,
895 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
897 0.353553390594f, 0.353553390594f, 0.5f,
898 -0.353553390594f, 0.353553390594f, 0.5f,
899 -0.353553390594f, -0.353553390594f, 0.5f,
900 0.353553390594f, -0.353553390594f, 0.5f,
905 0.353553390594f, 0.353553390594f, -0.5f,
906 -0.353553390594f, 0.353553390594f, -0.5f,
907 -0.353553390594f, -0.353553390594f, -0.5f,
908 0.353553390594f, -0.353553390594f, -0.5f
912 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
927 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
929 /* -- Tetrahedron -- */
930 /* Magic Numbers: r0 = ( 1, 0, 0 )
931 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
932 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
933 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
934 * |r0| = |r1| = |r2| = |r3| = 1
935 * Distance between any two points is 2 sqrt(6) / 3
937 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
939 #define TETRAHEDRON_NUM_VERT 4
940 #define TETRAHEDRON_NUM_FACES 4
941 #define TETRAHEDRON_NUM_EDGE_PER_FACE 3
942 #define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
943 #define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
944 #define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
946 /* Vertex Coordinates */
947 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
950 -0.333333333333f, 0.942809041582f, 0.0f,
951 -0.333333333333f, -0.471404520791f, 0.816496580928f,
952 -0.333333333333f, -0.471404520791f, -0.816496580928f
955 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
958 0.333333333333f, -0.942809041582f, 0.0f,
959 0.333333333333f, 0.471404520791f, -0.816496580928f,
960 0.333333333333f, 0.471404520791f, 0.816496580928f
964 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
971 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
973 /* -- Sierpinski Sponge -- */
974 static unsigned int ipow (int x, unsigned int y)
976 /* return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2); */
985 return (y%2? x: 1) * ipow(x*x, y/2);
990 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
993 if ( numLevels == 0 )
995 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
998 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
999 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
1001 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
1002 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
1004 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
1005 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
1006 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
1008 normals [outIdx ] = tetrahedron_n[normIdx ];
1009 normals [outIdx+1] = tetrahedron_n[normIdx+1];
1010 normals [outIdx+2] = tetrahedron_n[normIdx+2];
1014 else if ( numLevels > 0 )
1016 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
1017 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
1019 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
1022 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
1023 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
1024 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
1025 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
1030 /* -- Now the various non-polyhedra (shapes involving circles) -- */
1032 * Compute lookup table of cos and sin values forming a circle
1033 * (or half circle if halfCircle==TRUE)
1036 * It is the responsibility of the caller to free these tables
1037 * The size of the table is (n+1) to form a connected loop
1038 * The last entry is exactly the same as the first
1039 * The sign of n can be flipped to get the reverse loop
1041 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
1045 /* Table size, the sign of n flips the circle direction */
1046 const int size = abs(n);
1048 /* Determine the angle between samples */
1049 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
1051 /* Allocate memory for n samples, plus duplicate of first entry at the end */
1052 *sint = malloc(sizeof(GLfloat) * (size+1));
1053 *cost = malloc(sizeof(GLfloat) * (size+1));
1055 /* Bail out if memory allocation fails, fgError never returns */
1056 if (!(*sint) || !(*cost))
1060 fgError("Failed to allocate memory in fghCircleTable");
1063 /* Compute cos and sin around the circle */
1067 for (i=1; i<size; i++)
1069 (*sint)[i] = (GLfloat)sin(angle*i);
1070 (*cost)[i] = (GLfloat)cos(angle*i);
1076 (*sint)[size] = 0.0f; /* sin PI */
1077 (*cost)[size] = -1.0f; /* cos PI */
1081 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
1082 (*sint)[size] = (*sint)[0];
1083 (*cost)[size] = (*cost)[0];
1087 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
1090 int idx = 0; /* idx into vertex/normal buffer */
1093 /* Pre-computed circle */
1094 GLfloat *sint1,*cost1;
1095 GLfloat *sint2,*cost2;
1097 /* number of unique vertices */
1098 if (slices==0 || stacks<2)
1100 /* nothing to generate */
1104 *nVert = slices*(stacks-1)+2;
1105 if ((*nVert) > 65535)
1107 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1109 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1111 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
1113 /* precompute values on unit circle */
1114 fghCircleTable(&sint1,&cost1,-slices,FALSE);
1115 fghCircleTable(&sint2,&cost2, stacks,TRUE);
1117 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1118 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1119 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1120 if (!(*vertices) || !(*normals))
1124 fgError("Failed to allocate memory in fghGenerateSphere");
1128 (*vertices)[0] = 0.f;
1129 (*vertices)[1] = 0.f;
1130 (*vertices)[2] = radius;
1131 (*normals )[0] = 0.f;
1132 (*normals )[1] = 0.f;
1133 (*normals )[2] = 1.f;
1137 for( i=1; i<stacks; i++ )
1139 for(j=0; j<slices; j++, idx+=3)
1141 x = cost1[j]*sint2[i];
1142 y = sint1[j]*sint2[i];
1145 (*vertices)[idx ] = x*radius;
1146 (*vertices)[idx+1] = y*radius;
1147 (*vertices)[idx+2] = z*radius;
1148 (*normals )[idx ] = x;
1149 (*normals )[idx+1] = y;
1150 (*normals )[idx+2] = z;
1155 (*vertices)[idx ] = 0.f;
1156 (*vertices)[idx+1] = 0.f;
1157 (*vertices)[idx+2] = -radius;
1158 (*normals )[idx ] = 0.f;
1159 (*normals )[idx+1] = 0.f;
1160 (*normals )[idx+2] = -1.f;
1162 /* Done creating vertices, release sin and cos tables */
1169 void fghGenerateCone(
1170 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1171 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1175 int idx = 0; /* idx into vertex/normal buffer */
1177 /* Pre-computed circle */
1178 GLfloat *sint,*cost;
1180 /* Step in z and radius as stacks are drawn. */
1182 GLfloat r = (GLfloat)base;
1184 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1185 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1187 /* Scaling factors for vertex normals */
1188 const GLfloat cosn = (GLfloat) (height / sqrt( height * height + base * base ));
1189 const GLfloat sinn = (GLfloat) (base / sqrt( height * height + base * base ));
1193 /* number of unique vertices */
1194 if (slices==0 || stacks<1)
1196 /* nothing to generate */
1200 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1202 if ((*nVert) > 65535)
1204 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1206 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1208 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1210 /* Pre-computed circle */
1211 fghCircleTable(&sint,&cost,-slices,FALSE);
1213 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1214 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1215 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1216 if (!(*vertices) || !(*normals))
1220 fgError("Failed to allocate memory in fghGenerateCone");
1224 (*vertices)[0] = 0.f;
1225 (*vertices)[1] = 0.f;
1227 (*normals )[0] = 0.f;
1228 (*normals )[1] = 0.f;
1229 (*normals )[2] = -1.f;
1231 /* other on bottom (get normals right) */
1232 for (j=0; j<slices; j++, idx+=3)
1234 (*vertices)[idx ] = cost[j]*r;
1235 (*vertices)[idx+1] = sint[j]*r;
1236 (*vertices)[idx+2] = z;
1237 (*normals )[idx ] = 0.f;
1238 (*normals )[idx+1] = 0.f;
1239 (*normals )[idx+2] = -1.f;
1243 for (i=0; i<stacks+1; i++ )
1245 for (j=0; j<slices; j++, idx+=3)
1247 (*vertices)[idx ] = cost[j]*r;
1248 (*vertices)[idx+1] = sint[j]*r;
1249 (*vertices)[idx+2] = z;
1250 (*normals )[idx ] = cost[j]*sinn;
1251 (*normals )[idx+1] = sint[j]*sinn;
1252 (*normals )[idx+2] = cosn;
1259 /* Release sin and cos tables */
1264 void fghGenerateCylinder(
1265 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1266 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1270 int idx = 0; /* idx into vertex/normal buffer */
1272 /* Step in z as stacks are drawn. */
1273 GLfloat radf = (GLfloat)radius;
1275 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1277 /* Pre-computed circle */
1278 GLfloat *sint,*cost;
1280 /* number of unique vertices */
1281 if (slices==0 || stacks<1)
1283 /* nothing to generate */
1287 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1289 if ((*nVert) > 65535)
1291 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1293 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1295 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1297 /* Pre-computed circle */
1298 fghCircleTable(&sint,&cost,-slices,FALSE);
1300 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1301 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1302 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1303 if (!(*vertices) || !(*normals))
1307 fgError("Failed to allocate memory in fghGenerateCylinder");
1312 (*vertices)[0] = 0.f;
1313 (*vertices)[1] = 0.f;
1314 (*vertices)[2] = 0.f;
1315 (*normals )[0] = 0.f;
1316 (*normals )[1] = 0.f;
1317 (*normals )[2] = -1.f;
1319 /* other on top (get normals right) */
1320 for (j=0; j<slices; j++, idx+=3)
1322 (*vertices)[idx ] = cost[j]*radf;
1323 (*vertices)[idx+1] = sint[j]*radf;
1324 (*vertices)[idx+2] = z;
1325 (*normals )[idx ] = 0.f;
1326 (*normals )[idx+1] = 0.f;
1327 (*normals )[idx+2] = -1.f;
1331 for (i=0; i<stacks+1; i++ )
1333 for (j=0; j<slices; j++, idx+=3)
1335 (*vertices)[idx ] = cost[j]*radf;
1336 (*vertices)[idx+1] = sint[j]*radf;
1337 (*vertices)[idx+2] = z;
1338 (*normals )[idx ] = cost[j];
1339 (*normals )[idx+1] = sint[j];
1340 (*normals )[idx+2] = 0.f;
1346 /* other on bottom (get normals right) */
1348 for (j=0; j<slices; j++, idx+=3)
1350 (*vertices)[idx ] = cost[j]*radf;
1351 (*vertices)[idx+1] = sint[j]*radf;
1352 (*vertices)[idx+2] = z;
1353 (*normals )[idx ] = 0.f;
1354 (*normals )[idx+1] = 0.f;
1355 (*normals )[idx+2] = 1.f;
1359 (*vertices)[idx ] = 0.f;
1360 (*vertices)[idx+1] = 0.f;
1361 (*vertices)[idx+2] = height;
1362 (*normals )[idx ] = 0.f;
1363 (*normals )[idx+1] = 0.f;
1364 (*normals )[idx+2] = 1.f;
1366 /* Release sin and cos tables */
1371 void fghGenerateTorus(
1372 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1373 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1376 GLfloat iradius = (float)dInnerRadius;
1377 GLfloat oradius = (float)dOuterRadius;
1380 /* Pre-computed circle */
1381 GLfloat *spsi, *cpsi;
1382 GLfloat *sphi, *cphi;
1384 /* number of unique vertices */
1385 if (nSides<2 || nRings<2)
1387 /* nothing to generate */
1391 *nVert = nSides * nRings;
1393 if ((*nVert) > 65535)
1395 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1397 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1399 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1401 /* precompute values on unit circle */
1402 fghCircleTable(&spsi,&cpsi, nRings,FALSE);
1403 fghCircleTable(&sphi,&cphi,-nSides,FALSE);
1405 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1406 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1407 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1408 if (!(*vertices) || !(*normals))
1412 fgError("Failed to allocate memory in fghGenerateTorus");
1415 for( j=0; j<nRings; j++ )
1417 for( i=0; i<nSides; i++ )
1419 int offset = 3 * ( j * nSides + i ) ;
1421 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1422 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1423 (*vertices)[offset+2] = sphi[i] * iradius ;
1424 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1425 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1426 (*normals )[offset+2] = sphi[i] ;
1430 /* Release sin and cos tables */
1437 /* -- INTERNAL DRAWING functions --------------------------------------- */
1438 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1439 static void fgh##nameICaps( GLboolean useWireMode )\
1443 fgh##nameICaps##Generate();\
1444 name##Cached = GL_TRUE;\
1449 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1450 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1455 fghDrawGeometrySolid(name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ,\
1456 vertIdxs, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1459 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1460 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1462 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1469 cubeCached = GL_TRUE;
1474 /* Need to build new vertex list containing vertices for cube of different size */
1477 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1479 /* Bail out if memory allocation fails, fgError never returns */
1483 fgError("Failed to allocate memory in fghCube");
1486 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1487 vertices[i] = dSize*cube_verts[i];
1490 vertices = cube_verts;
1493 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1494 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1497 fghDrawGeometrySolid(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1498 cube_vertIdxs, 1, CUBE_VERT_PER_OBJ_TRI);
1501 /* cleanup allocated memory */
1505 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1506 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1507 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1508 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1509 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1511 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1515 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1516 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1517 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1521 /* Allocate memory */
1522 vertices = malloc(numVert*3 * sizeof(GLfloat));
1523 normals = malloc(numVert*3 * sizeof(GLfloat));
1524 /* Bail out if memory allocation fails, fgError never returns */
1525 if (!vertices || !normals)
1529 fgError("Failed to allocate memory in fghSierpinskiSponge");
1532 /* Generate elements */
1533 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1535 /* Draw and cleanup */
1537 fghDrawGeometryWire (vertices,normals,numVert,
1538 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1541 fghDrawGeometrySolid(vertices,normals,numVert,NULL,1,0);
1549 static void fghSphere( GLfloat radius, GLint slices, GLint stacks, GLboolean useWireMode )
1552 GLfloat *vertices, *normals;
1554 /* Generate vertices and normals */
1555 fghGenerateSphere(radius,slices,stacks,&vertices,&normals,&nVert);
1558 /* nothing to draw */
1563 GLushort *sliceIdx, *stackIdx;
1564 /* First, generate vertex index arrays for drawing with glDrawElements
1565 * We have a bunch of line_loops to draw for each stack, and a
1566 * bunch for each slice.
1569 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1570 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1571 if (!(stackIdx) || !(sliceIdx))
1575 fgError("Failed to allocate memory in fghSphere");
1578 /* generate for each stack */
1579 for (i=0,idx=0; i<stacks-1; i++)
1581 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1582 for (j=0; j<slices; j++, idx++)
1584 stackIdx[idx] = offset+j;
1588 /* generate for each slice */
1589 for (i=0,idx=0; i<slices; i++)
1591 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1592 sliceIdx[idx++] = 0; /* vertex on top */
1593 for (j=0; j<stacks-1; j++, idx++)
1595 sliceIdx[idx] = offset+j*slices;
1597 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1601 fghDrawGeometryWire(vertices,normals,nVert,
1602 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1603 stackIdx,stacks-1,slices);
1605 /* cleanup allocated memory */
1611 /* First, generate vertex index arrays for drawing with glDrawElements
1612 * All stacks, including top and bottom are covered with a triangle
1616 /* Create index vector */
1619 /* Allocate buffers for indices, bail out if memory allocation fails */
1620 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1624 fgError("Failed to allocate memory in fghSphere");
1628 for (j=0, idx=0; j<slices; j++, idx+=2)
1630 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1631 stripIdx[idx+1] = 0;
1633 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1634 stripIdx[idx+1] = 0;
1637 /* middle stacks: */
1638 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1639 for (i=0; i<stacks-2; i++, idx+=2)
1641 offset = 1+i*slices; /* triangle_strip indices 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+=2)
1644 stripIdx[idx ] = offset+j+slices;
1645 stripIdx[idx+1] = offset+j;
1647 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1648 stripIdx[idx+1] = offset;
1652 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 */
1653 for (j=0; j<slices; j++, idx+=2)
1655 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1656 stripIdx[idx+1] = offset+j;
1658 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1659 stripIdx[idx+1] = offset;
1663 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks,(slices+1)*2);
1665 /* cleanup allocated memory */
1669 /* cleanup allocated memory */
1674 static void fghCone( GLfloat base, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1677 GLfloat *vertices, *normals;
1679 /* Generate vertices and normals */
1680 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1681 fghGenerateCone(base,height,slices,stacks,&vertices,&normals,&nVert);
1684 /* nothing to draw */
1689 GLushort *sliceIdx, *stackIdx;
1690 /* First, generate vertex index arrays for drawing with glDrawElements
1691 * We have a bunch of line_loops to draw for each stack, and a
1692 * bunch for each slice.
1695 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1696 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1697 if (!(stackIdx) || !(sliceIdx))
1701 fgError("Failed to allocate memory in fghCone");
1704 /* generate for each stack */
1705 for (i=0,idx=0; i<stacks; i++)
1707 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1708 for (j=0; j<slices; j++, idx++)
1710 stackIdx[idx] = offset+j;
1714 /* generate for each slice */
1715 for (i=0,idx=0; i<slices; i++)
1717 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1718 sliceIdx[idx++] = offset+slices;
1719 sliceIdx[idx++] = offset+(stacks+1)*slices;
1723 fghDrawGeometryWire(vertices,normals,nVert,
1724 sliceIdx,1,slices*2,GL_LINES,
1725 stackIdx,stacks,slices);
1727 /* cleanup allocated memory */
1733 /* First, generate vertex index arrays for drawing with glDrawElements
1734 * All stacks, including top and bottom are covered with a triangle
1738 /* Create index vector */
1741 /* Allocate buffers for indices, bail out if memory allocation fails */
1742 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1746 fgError("Failed to allocate memory in fghCone");
1750 for (j=0, idx=0; j<slices; j++, idx+=2)
1753 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1755 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1756 stripIdx[idx+1] = 1;
1759 /* middle stacks: */
1760 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1761 for (i=0; i<stacks; i++, idx+=2)
1763 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 */
1764 for (j=0; j<slices; j++, idx+=2)
1766 stripIdx[idx ] = offset+j;
1767 stripIdx[idx+1] = offset+j+slices;
1769 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1770 stripIdx[idx+1] = offset+slices;
1774 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+1,(slices+1)*2);
1776 /* cleanup allocated memory */
1780 /* cleanup allocated memory */
1785 static void fghCylinder( GLfloat radius, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1788 GLfloat *vertices, *normals;
1790 /* Generate vertices and normals */
1791 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1792 fghGenerateCylinder(radius,height,slices,stacks,&vertices,&normals,&nVert);
1795 /* nothing to draw */
1800 GLushort *sliceIdx, *stackIdx;
1801 /* First, generate vertex index arrays for drawing with glDrawElements
1802 * We have a bunch of line_loops to draw for each stack, and a
1803 * bunch for each slice.
1806 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1807 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1808 if (!(stackIdx) || !(sliceIdx))
1812 fgError("Failed to allocate memory in fghCylinder");
1815 /* generate for each stack */
1816 for (i=0,idx=0; i<stacks+1; i++)
1818 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1819 for (j=0; j<slices; j++, idx++)
1821 stackIdx[idx] = offset+j;
1825 /* generate for each slice */
1826 for (i=0,idx=0; i<slices; i++)
1828 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1829 sliceIdx[idx++] = offset+slices;
1830 sliceIdx[idx++] = offset+(stacks+1)*slices;
1834 fghDrawGeometryWire(vertices,normals,nVert,
1835 sliceIdx,1,slices*2,GL_LINES,
1836 stackIdx,stacks+1,slices);
1838 /* cleanup allocated memory */
1844 /* First, generate vertex index arrays for drawing with glDrawElements
1845 * All stacks, including top and bottom are covered with a triangle
1849 /* Create index vector */
1852 /* Allocate buffers for indices, bail out if memory allocation fails */
1853 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1857 fgError("Failed to allocate memory in fghCylinder");
1861 for (j=0, idx=0; j<slices; j++, idx+=2)
1864 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1866 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1867 stripIdx[idx+1] = 1;
1870 /* middle stacks: */
1871 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1872 for (i=0; i<stacks; i++, idx+=2)
1874 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 */
1875 for (j=0; j<slices; j++, idx+=2)
1877 stripIdx[idx ] = offset+j;
1878 stripIdx[idx+1] = offset+j+slices;
1880 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1881 stripIdx[idx+1] = offset+slices;
1885 offset = 1+(stacks+2)*slices;
1886 for (j=0; j<slices; j++, idx+=2)
1888 stripIdx[idx ] = offset+j;
1889 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1891 stripIdx[idx ] = offset;
1892 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1895 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+2,(slices+1)*2);
1897 /* cleanup allocated memory */
1901 /* cleanup allocated memory */
1906 static void fghTorus( GLfloat dInnerRadius, GLfloat dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1909 GLfloat *vertices, *normals;
1911 /* Generate vertices and normals */
1912 fghGenerateTorus(dInnerRadius,dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1915 /* nothing to draw */
1920 GLushort *sideIdx, *ringIdx;
1921 /* First, generate vertex index arrays for drawing with glDrawElements
1922 * We have a bunch of line_loops to draw each side, and a
1923 * bunch for each ring.
1926 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1927 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1928 if (!(ringIdx) || !(sideIdx))
1932 fgError("Failed to allocate memory in fghTorus");
1935 /* generate for each ring */
1936 for( j=0,idx=0; j<nRings; j++ )
1937 for( i=0; i<nSides; i++, idx++ )
1938 ringIdx[idx] = j * nSides + i;
1940 /* generate for each side */
1941 for( i=0,idx=0; i<nSides; i++ )
1942 for( j=0; j<nRings; j++, idx++ )
1943 sideIdx[idx] = j * nSides + i;
1946 fghDrawGeometryWire(vertices,normals,nVert,
1947 ringIdx,nRings,nSides,GL_LINE_LOOP,
1948 sideIdx,nSides,nRings);
1950 /* cleanup allocated memory */
1956 /* First, generate vertex index arrays for drawing with glDrawElements
1957 * All stacks, including top and bottom are covered with a triangle
1962 /* Allocate buffers for indices, bail out if memory allocation fails */
1963 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
1967 fgError("Failed to allocate memory in fghTorus");
1970 for( i=0, idx=0; i<nSides; i++ )
1976 for( j=0; j<nRings; j++, idx+=2 )
1978 int offset = j * nSides + i;
1979 stripIdx[idx ] = offset;
1980 stripIdx[idx+1] = offset + ioff;
1982 /* repeat first to close off shape */
1984 stripIdx[idx+1] = i + ioff;
1989 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,nSides,(nRings+1)*2);
1991 /* cleanup allocated memory */
1995 /* cleanup allocated memory */
2001 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
2005 * Draws a solid sphere
2007 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
2009 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
2010 fghSphere((GLfloat)radius, slices, stacks, FALSE );
2014 * Draws a wire sphere
2016 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
2018 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
2019 fghSphere((GLfloat)radius, slices, stacks, TRUE );
2024 * Draws a solid cone
2026 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
2028 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
2029 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, FALSE );
2035 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
2037 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
2038 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, TRUE );
2043 * Draws a solid cylinder
2045 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
2047 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
2048 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, FALSE );
2052 * Draws a wire cylinder
2054 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
2056 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
2057 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, TRUE );
2061 * Draws a wire torus
2063 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2065 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
2066 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, TRUE);
2070 * Draws a solid torus
2072 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2074 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
2075 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, FALSE);
2080 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
2081 /* Macro to generate interface functions */
2082 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
2083 void FGAPIENTRY glutWire##nameICaps( void )\
2085 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
2086 fgh##nameICaps( TRUE );\
2088 void FGAPIENTRY glutSolid##nameICaps( void )\
2090 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
2091 fgh##nameICaps( FALSE );\
2094 void FGAPIENTRY glutWireCube( double dSize )
2096 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
2097 fghCube( (GLfloat)dSize, TRUE );
2099 void FGAPIENTRY glutSolidCube( double dSize )
2101 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
2102 fghCube( (GLfloat)dSize, FALSE );
2105 DECLARE_SHAPE_INTERFACE(Dodecahedron)
2106 DECLARE_SHAPE_INTERFACE(Icosahedron)
2107 DECLARE_SHAPE_INTERFACE(Octahedron)
2108 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
2110 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
2112 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
2113 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
2115 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
2117 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
2118 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
2121 DECLARE_SHAPE_INTERFACE(Tetrahedron)
2124 /*** END OF FILE ***/