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 #ifndef GL_ES_VERSION_2_0
55 static void fghDrawNormalVisualization11();
57 static void fghDrawNormalVisualization20(GLint attribute_v_coord);
60 * Explanation of the functions has to be separate for the polyhedra and
61 * the non-polyhedra (objects with a circular cross-section).
63 * - We have only implemented the five platonic solids and the rhomboid
64 * dodecahedron. If you need more types of polyhedra, please see
66 * - Solids are drawn by glDrawArrays if composed of triangular faces
67 * (the tetrahedron, octahedron, and icosahedron), or are first
68 * decomposed into triangles and then drawn by glDrawElements if its
69 * faces are squares or pentagons (cube, dodecahedron and rhombic
70 * dodecahedron) as some vertices are repeated in that case.
71 * - WireFrame drawing is done using a GL_LINE_LOOP per face, and thus
72 * issuing one draw call per face. glDrawArrays is always used as no
73 * triangle decomposition is needed to draw faces. We use the "first"
74 * parameter in glDrawArrays to go from face to face.
77 * - We have implemented the sphere, cylinder, cone and torus.
78 * - All shapes are characterized by two parameters: the number of
79 * subdivisions along two axes used to construct the shape's vertices
80 * (e.g. stacks and slices for the sphere).
81 * As different subdivisions are most suitable for different shapes,
82 * and are thus also named differently, I wont provide general comments
84 * - Solids are drawn using glDrawArrays and GL_TRIANGLE_STRIP. Each
85 * strip covers one revolution around one of the two subdivision axes
87 * - WireFrame drawing is done for the subdivisions along the two axes
88 * separately, usually using GL_LINE_LOOP. Vertex index arrays are
89 * built containing the vertices to be drawn for each loop, which are
90 * then drawn using multiple calls to glDrawElements. As the number of
91 * subdivisions along the two axes is not guaranteed to be equal, the
92 * vertex indices for e.g. stacks and slices are stored in separate
93 * arrays, which makes the input to the drawing function a bit clunky,
94 * but allows for the same drawing function to be used for all shapes.
99 * Draw geometric shape in wire mode (only edges)
102 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
103 * The vertex coordinate and normal buffers, and the number of entries in
106 * a vertex indices buffer, optional (never passed for the polyhedra)
107 * GLsizei numParts, GLsizei numVertPerPart
108 * polyhedra: number of faces, and the number of vertices for drawing
110 * non-polyhedra: number of edges to draw for first subdivision (not
111 * necessarily equal to number of subdivisions requested by user, e.g.
112 * as each subdivision is enclosed by two edges), and number of
113 * vertices for drawing each
114 * numParts * numVertPerPart gives the number of entries in the vertex
117 * vertex drawing mode (e.g. always GL_LINE_LOOP for polyhedra, varies
119 * GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
120 * non-polyhedra only: same as the above, but now for subdivisions along
121 * the other axis. Always drawn as GL_LINE_LOOP.
123 * Feel free to contribute better naming ;)
125 static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
126 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
127 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
130 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
131 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
133 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
134 /* User requested a 2.0 draw */
135 fghDrawGeometryWire20(vertices, normals, numVertices,
136 vertIdxs, numParts, numVertPerPart, vertexMode,
137 vertIdxs2, numParts2, numVertPerPart2,
138 attribute_v_coord, attribute_v_normal);
139 #ifndef GL_ES_VERSION_2_0
141 fghDrawGeometryWire11(vertices, normals,
142 vertIdxs, numParts, numVertPerPart, vertexMode,
143 vertIdxs2, numParts2, numVertPerPart2);
147 /* Draw the geometric shape with filled triangles
150 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
151 * The vertex coordinate and normal buffers, and the number of entries in
154 * a vertex indices buffer, optional (not passed for the polyhedra with
156 * GLsizei numParts, GLsizei numVertPerPart
157 * polyhedra: not used for polyhedra with triangular faces
158 (numEdgePerFace==3), as each vertex+normal pair is drawn only once,
159 so no vertex indices are used.
160 Else, the shape was triangulated (DECOMPOSE_TO_TRIANGLE), leading to
161 reuse of some vertex+normal pairs, and thus the need to draw with
162 glDrawElements. numParts is always 1 in this case (we can draw the
163 whole object with one call to glDrawElements as the vertex index
164 array contains separate triangles), and numVertPerPart indicates
165 the number of vertex indices in the vertex array.
166 * non-polyhedra: number of parts (GL_TRIANGLE_STRIPs) to be drawn
167 separately (numParts calls to glDrawElements) to create the object.
168 numVertPerPart indicates the number of vertex indices to be
169 processed at each draw call.
170 * numParts * numVertPerPart gives the number of entries in the vertex
173 static void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
174 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
176 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
177 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
179 if (fgStructure.CurrentWindow->State.VisualizeNormals)
180 /* generate normals for each vertex to be drawn as well */
181 fghGenerateNormalVisualization(vertices, normals, numVertices,
182 vertIdxs, numParts, numVertIdxsPerPart);
184 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
186 /* User requested a 2.0 draw */
187 fghDrawGeometrySolid20(vertices, normals, numVertices,
188 vertIdxs, numParts, numVertIdxsPerPart,
189 attribute_v_coord, attribute_v_normal);
191 if (fgStructure.CurrentWindow->State.VisualizeNormals)
192 /* draw normals for each vertex as well */
193 fghDrawNormalVisualization20(attribute_v_coord);
195 #ifndef GL_ES_VERSION_2_0
198 fghDrawGeometrySolid11(vertices, normals, numVertices,
199 vertIdxs, numParts, numVertIdxsPerPart);
201 if (fgStructure.CurrentWindow->State.VisualizeNormals)
202 /* draw normals for each vertex as well */
203 fghDrawNormalVisualization11();
210 /* Version for OpenGL (ES) 1.1 */
211 #ifndef GL_ES_VERSION_2_0
212 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
213 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
214 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
219 glEnableClientState(GL_VERTEX_ARRAY);
220 glEnableClientState(GL_NORMAL_ARRAY);
222 glVertexPointer(3, GL_FLOAT, 0, vertices);
223 glNormalPointer(GL_FLOAT, 0, normals);
227 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
228 for (i=0; i<numParts; i++)
229 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
231 for (i=0; i<numParts; i++)
232 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
235 for (i=0; i<numParts2; i++)
236 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
238 glDisableClientState(GL_VERTEX_ARRAY);
239 glDisableClientState(GL_NORMAL_ARRAY);
243 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
244 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
248 glEnableClientState(GL_VERTEX_ARRAY);
249 glEnableClientState(GL_NORMAL_ARRAY);
251 glVertexPointer(3, GL_FLOAT, 0, vertices);
252 glNormalPointer(GL_FLOAT, 0, normals);
255 glDrawArrays(GL_TRIANGLES, 0, numVertices);
258 for (i=0; i<numParts; i++)
259 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
261 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
263 glDisableClientState(GL_VERTEX_ARRAY);
264 glDisableClientState(GL_NORMAL_ARRAY);
268 /* Version for OpenGL (ES) >= 2.0 */
269 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
270 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
271 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
272 GLint attribute_v_coord, GLint attribute_v_normal)
274 GLuint vbo_coords = 0, vbo_normals = 0,
275 ibo_elements = 0, ibo_elements2 = 0;
276 GLsizei numVertIdxs = numParts * numVertPerPart;
277 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
280 if (numVertices > 0 && attribute_v_coord != -1) {
281 fghGenBuffers(1, &vbo_coords);
282 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
283 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
284 vertices, FGH_STATIC_DRAW);
287 if (numVertices > 0 && attribute_v_normal != -1) {
288 fghGenBuffers(1, &vbo_normals);
289 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
290 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
291 normals, FGH_STATIC_DRAW);
294 if (vertIdxs != NULL) {
295 fghGenBuffers(1, &ibo_elements);
296 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
297 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
298 vertIdxs, FGH_STATIC_DRAW);
299 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
302 if (vertIdxs2 != NULL) {
303 fghGenBuffers(1, &ibo_elements2);
304 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
305 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
306 vertIdxs2, FGH_STATIC_DRAW);
307 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
311 fghEnableVertexAttribArray(attribute_v_coord);
312 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
313 fghVertexAttribPointer(
314 attribute_v_coord, /* attribute */
315 3, /* number of elements per vertex, here (x,y,z) */
316 GL_FLOAT, /* the type of each element */
317 GL_FALSE, /* take our values as-is */
318 0, /* no extra data between each position */
319 0 /* offset of first element */
321 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
325 fghEnableVertexAttribArray(attribute_v_normal);
326 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
327 fghVertexAttribPointer(
328 attribute_v_normal, /* attribute */
329 3, /* number of elements per vertex, here (x,y,z) */
330 GL_FLOAT, /* the type of each element */
331 GL_FALSE, /* take our values as-is */
332 0, /* no extra data between each position */
333 0 /* offset of first element */
335 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
339 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
340 for (i=0; i<numParts; i++)
341 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
343 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
344 for (i=0; i<numParts; i++)
345 glDrawElements(vertexMode, numVertPerPart,
346 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
347 /* Clean existing bindings before clean-up */
348 /* Android showed instability otherwise */
349 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
353 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
354 for (i=0; i<numParts2; i++)
355 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
356 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
357 /* Clean existing bindings before clean-up */
358 /* Android showed instability otherwise */
359 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
363 fghDisableVertexAttribArray(attribute_v_coord);
364 if (vbo_normals != 0)
365 fghDisableVertexAttribArray(attribute_v_normal);
368 fghDeleteBuffers(1, &vbo_coords);
369 if (vbo_normals != 0)
370 fghDeleteBuffers(1, &vbo_normals);
371 if (ibo_elements != 0)
372 fghDeleteBuffers(1, &ibo_elements);
373 if (ibo_elements2 != 0)
374 fghDeleteBuffers(1, &ibo_elements2);
380 /* Version for OpenGL (ES) >= 2.0 */
381 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
382 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
383 GLint attribute_v_coord, GLint attribute_v_normal)
385 GLuint vbo_coords = 0, vbo_normals = 0, ibo_elements = 0;
386 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
389 if (numVertices > 0 && attribute_v_coord != -1) {
390 fghGenBuffers(1, &vbo_coords);
391 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
392 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
393 vertices, FGH_STATIC_DRAW);
394 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
397 if (numVertices > 0 && attribute_v_normal != -1) {
398 fghGenBuffers(1, &vbo_normals);
399 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
400 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
401 normals, FGH_STATIC_DRAW);
402 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
405 if (vertIdxs != NULL) {
406 fghGenBuffers(1, &ibo_elements);
407 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
408 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
409 vertIdxs, FGH_STATIC_DRAW);
410 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
414 fghEnableVertexAttribArray(attribute_v_coord);
415 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
416 fghVertexAttribPointer(
417 attribute_v_coord, /* attribute */
418 3, /* number of elements per vertex, here (x,y,z) */
419 GL_FLOAT, /* the type of each element */
420 GL_FALSE, /* take our values as-is */
421 0, /* no extra data between each position */
422 0 /* offset of first element */
424 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
428 fghEnableVertexAttribArray(attribute_v_normal);
429 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
430 fghVertexAttribPointer(
431 attribute_v_normal, /* attribute */
432 3, /* number of elements per vertex, here (x,y,z) */
433 GL_FLOAT, /* the type of each element */
434 GL_FALSE, /* take our values as-is */
435 0, /* no extra data between each position */
436 0 /* offset of first element */
438 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
441 if (vertIdxs == NULL) {
442 glDrawArrays(GL_TRIANGLES, 0, numVertices);
444 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
446 for (i=0; i<numParts; i++) {
447 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
450 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
452 /* Clean existing bindings before clean-up */
453 /* Android showed instability otherwise */
454 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
458 fghDisableVertexAttribArray(attribute_v_coord);
459 if (vbo_normals != 0)
460 fghDisableVertexAttribArray(attribute_v_normal);
463 fghDeleteBuffers(1, &vbo_coords);
464 if (vbo_normals != 0)
465 fghDeleteBuffers(1, &vbo_normals);
466 if (ibo_elements != 0)
467 fghDeleteBuffers(1, &ibo_elements);
473 * Generate vertex indices for visualizing the normals.
475 static GLfloat *verticesForNormalVisualization;
476 static GLushort numNormalVertices = 0;
477 static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
478 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
481 /* calc number of vertices to generate, allocate. TODO: FREE again after draw!
482 * two for each vertex in the input shape
485 numNormalVertices = numVertices * 2;
487 numNormalVertices = numParts * numVertIdxsPerPart * 2;
488 verticesForNormalVisualization = malloc(numNormalVertices*3 * sizeof(GLfloat));
490 /* Now generate vertices for lines to draw the normals */
493 for (i=0,j=0; i<numNormalVertices*3/2; i+=3, j+=6)
495 verticesForNormalVisualization[j+0] = vertices[i+0];
496 verticesForNormalVisualization[j+1] = vertices[i+1];
497 verticesForNormalVisualization[j+2] = vertices[i+2];
498 verticesForNormalVisualization[j+3] = vertices[i+0] + normals[i+0]/4.f;
499 verticesForNormalVisualization[j+4] = vertices[i+1] + normals[i+1]/4.f;
500 verticesForNormalVisualization[j+5] = vertices[i+2] + normals[i+2]/4.f;
505 for (i=0,j=0; i<numNormalVertices/2; i++, j+=6)
507 GLushort idx = vertIdxs[i]*3;
508 verticesForNormalVisualization[j+0] = vertices[idx+0];
509 verticesForNormalVisualization[j+1] = vertices[idx+1];
510 verticesForNormalVisualization[j+2] = vertices[idx+2];
511 verticesForNormalVisualization[j+3] = vertices[idx+0] + normals[idx+0]/4.f;
512 verticesForNormalVisualization[j+4] = vertices[idx+1] + normals[idx+1]/4.f;
513 verticesForNormalVisualization[j+5] = vertices[idx+2] + normals[idx+2]/4.f;
518 /* Version for OpenGL (ES) 1.1 */
519 #ifndef GL_ES_VERSION_2_0
520 static void fghDrawNormalVisualization11()
522 GLfloat currentColor[4];
523 /* Setup draw color: (1,1,1)-shape's color */
524 glGetFloatv(GL_CURRENT_COLOR,currentColor);
525 glColor4f(1-currentColor[0],1-currentColor[1],1-currentColor[2],currentColor[3]);
527 glEnableClientState(GL_VERTEX_ARRAY);
529 glVertexPointer(3, GL_FLOAT, 0, verticesForNormalVisualization);
530 glDrawArrays(GL_LINES, 0, numNormalVertices);
532 glDisableClientState(GL_VERTEX_ARRAY);
534 /* Done, free memory, reset color */
535 free(verticesForNormalVisualization);
536 glColor4fv(currentColor);
540 /* Version for OpenGL (ES) >= 2.0 */
541 static void fghDrawNormalVisualization20(GLint attribute_v_coord)
543 GLuint vbo_coords = 0;
545 if (attribute_v_coord != -1) {
546 fghGenBuffers(1, &vbo_coords);
547 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
548 fghBufferData(FGH_ARRAY_BUFFER, numNormalVertices * 3 * sizeof(verticesForNormalVisualization[0]),
549 verticesForNormalVisualization, FGH_STATIC_DRAW);
554 fghEnableVertexAttribArray(attribute_v_coord);
555 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
556 fghVertexAttribPointer(
557 attribute_v_coord, /* attribute */
558 3, /* number of elements per vertex, here (x,y,z) */
559 GL_FLOAT, /* the type of each element */
560 GL_FALSE, /* take our values as-is */
561 0, /* no extra data between each position */
562 0 /* offset of first element */
564 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
567 glDrawArrays(GL_LINES, 0, numNormalVertices);
570 fghDisableVertexAttribArray(attribute_v_coord);
573 fghDeleteBuffers(1, &vbo_coords);
575 /* Done, free memory */
576 free(verticesForNormalVisualization);
580 * Generate all combinations of vertices and normals needed to draw object.
581 * Optional shape decomposition to triangles:
582 * We'll use glDrawElements to draw all shapes that are not naturally
583 * composed of triangles, so generate an index vector here, using the
584 * below sampling scheme.
585 * Be careful to keep winding of all triangles counter-clockwise,
586 * assuming that input has correct winding...
588 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
589 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
591 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
593 int i,j,numEdgeIdxPerFace;
594 GLubyte *vertSamps = NULL;
595 switch (numEdgePerFace)
598 /* nothing to do here, we'll draw with glDrawArrays */
601 vertSamps = vert4Decomp;
602 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
605 vertSamps = vert5Decomp;
606 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
610 * Build array with vertices using vertex coordinates and vertex indices
611 * Do same for normals.
612 * Need to do this because of different normals at shared vertices.
614 for (i=0; i<numFaces; i++)
617 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
618 for (j=0; j<numEdgePerFace; j++)
620 int outIdx = i*numEdgePerFace*3+j*3;
621 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
623 vertOut[outIdx ] = vertices[vertIdx ];
624 vertOut[outIdx+1] = vertices[vertIdx+1];
625 vertOut[outIdx+2] = vertices[vertIdx+2];
627 normOut[outIdx ] = normals [normIdx ];
628 normOut[outIdx+1] = normals [normIdx+1];
629 normOut[outIdx+2] = normals [normIdx+2];
632 /* generate vertex indices for each face */
634 for (j=0; j<numEdgeIdxPerFace; j++)
635 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
639 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
641 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
642 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
646 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
647 /* -- stuff that can be cached -- */
648 /* Cache of input to glDrawArrays or glDrawElements
649 * In general, we build arrays with all vertices or normals.
650 * We cant compress this and use glDrawElements as all combinations of
651 * vertices and normals are unique.
653 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
654 static GLboolean name##Cached = FALSE;\
655 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
656 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
657 static void fgh##nameICaps##Generate()\
659 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
660 name##_v, name##_vi, name##_n,\
661 name##_verts, name##_norms);\
663 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
664 static GLboolean name##Cached = FALSE;\
665 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
666 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
667 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
668 static void fgh##nameICaps##Generate()\
670 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
671 name##_v, name##_vi, name##_n,\
672 name##_verts, name##_norms, name##_vertIdxs);\
676 #define CUBE_NUM_VERT 8
677 #define CUBE_NUM_FACES 6
678 #define CUBE_NUM_EDGE_PER_FACE 4
679 #define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
680 #define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
681 #define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
682 /* Vertex Coordinates */
683 static GLfloat cube_v[CUBE_NUM_VERT*3] =
695 static GLfloat cube_n[CUBE_NUM_FACES*3] =
705 /* Vertex indices, as quads, before triangulation */
706 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
715 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
717 /* -- Dodecahedron -- */
718 /* Magic Numbers: It is possible to create a dodecahedron by attaching two
719 * pentagons to each face of of a cube. The coordinates of the points are:
720 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
721 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
722 * x = 0.61803398875 and z = 1.61803398875.
724 #define DODECAHEDRON_NUM_VERT 20
725 #define DODECAHEDRON_NUM_FACES 12
726 #define DODECAHEDRON_NUM_EDGE_PER_FACE 5
727 #define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
728 #define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
729 #define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
730 /* Vertex Coordinates */
731 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
733 0.0f, 1.61803398875f, 0.61803398875f,
735 -0.61803398875f, 0.0f, 1.61803398875f,
736 0.61803398875f, 0.0f, 1.61803398875f,
738 0.0f, 1.61803398875f, -0.61803398875f,
740 0.61803398875f, 0.0f, -1.61803398875f,
741 -0.61803398875f, 0.0f, -1.61803398875f,
742 - 1.0f, 1.0f, - 1.0f,
743 0.0f, -1.61803398875f, 0.61803398875f,
745 - 1.0f, - 1.0f, 1.0f,
746 0.0f, -1.61803398875f, -0.61803398875f,
747 - 1.0f, - 1.0f, - 1.0f,
748 1.0f, - 1.0f, - 1.0f,
749 1.61803398875f, -0.61803398875f, 0.0f,
750 1.61803398875f, 0.61803398875f, 0.0f,
751 -1.61803398875f, 0.61803398875f, 0.0f,
752 -1.61803398875f, -0.61803398875f, 0.0f
755 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
757 0.0f, 0.525731112119f, 0.850650808354f,
758 0.0f, 0.525731112119f, -0.850650808354f,
759 0.0f, -0.525731112119f, 0.850650808354f,
760 0.0f, -0.525731112119f, -0.850650808354f,
762 0.850650808354f, 0.0f, 0.525731112119f,
763 -0.850650808354f, 0.0f, 0.525731112119f,
764 0.850650808354f, 0.0f, -0.525731112119f,
765 -0.850650808354f, 0.0f, -0.525731112119f,
767 0.525731112119f, 0.850650808354f, 0.0f,
768 0.525731112119f, -0.850650808354f, 0.0f,
769 -0.525731112119f, 0.850650808354f, 0.0f,
770 -0.525731112119f, -0.850650808354f, 0.0f,
774 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
791 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
794 /* -- Icosahedron -- */
795 #define ICOSAHEDRON_NUM_VERT 12
796 #define ICOSAHEDRON_NUM_FACES 20
797 #define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
798 #define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
799 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
800 #define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
801 /* Vertex Coordinates */
802 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
805 0.447213595500f, 0.894427191000f, 0.0f,
806 0.447213595500f, 0.276393202252f, 0.850650808354f,
807 0.447213595500f, -0.723606797748f, 0.525731112119f,
808 0.447213595500f, -0.723606797748f, -0.525731112119f,
809 0.447213595500f, 0.276393202252f, -0.850650808354f,
810 -0.447213595500f, -0.894427191000f, 0.0f,
811 -0.447213595500f, -0.276393202252f, 0.850650808354f,
812 -0.447213595500f, 0.723606797748f, 0.525731112119f,
813 -0.447213595500f, 0.723606797748f, -0.525731112119f,
814 -0.447213595500f, -0.276393202252f, -0.850650808354f,
818 * 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] ) ;
819 * 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] ) ;
820 * 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] ) ;
822 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
824 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
825 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
826 0.760845213033849f, -0.581234022404097f, 0.0f,
827 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
828 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
829 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
830 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
831 0.179611190633958f, -0.940456403667806f, 0.0f,
832 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
833 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
834 -0.179611190633958f, 0.940456403667806f, 0.0f,
835 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
836 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
837 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
838 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
839 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
840 -0.760845213033849f, 0.581234022404097f, 0.0f,
841 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
842 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
843 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
847 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
870 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
872 /* -- Octahedron -- */
873 #define OCTAHEDRON_NUM_VERT 6
874 #define OCTAHEDRON_NUM_FACES 8
875 #define OCTAHEDRON_NUM_EDGE_PER_FACE 3
876 #define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
877 #define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
878 #define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
880 /* Vertex Coordinates */
881 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
892 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
894 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
895 0.577350269189f, 0.577350269189f,-0.577350269189f,
896 0.577350269189f,-0.577350269189f, 0.577350269189f,
897 0.577350269189f,-0.577350269189f,-0.577350269189f,
898 -0.577350269189f, 0.577350269189f, 0.577350269189f,
899 -0.577350269189f, 0.577350269189f,-0.577350269189f,
900 -0.577350269189f,-0.577350269189f, 0.577350269189f,
901 -0.577350269189f,-0.577350269189f,-0.577350269189f
906 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
917 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
919 /* -- RhombicDodecahedron -- */
920 #define RHOMBICDODECAHEDRON_NUM_VERT 14
921 #define RHOMBICDODECAHEDRON_NUM_FACES 12
922 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
923 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
924 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
925 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
927 /* Vertex Coordinates */
928 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
931 0.707106781187f, 0.0f, 0.5f,
932 0.0f, 0.707106781187f, 0.5f,
933 -0.707106781187f, 0.0f, 0.5f,
934 0.0f, -0.707106781187f, 0.5f,
935 0.707106781187f, 0.707106781187f, 0.0f,
936 -0.707106781187f, 0.707106781187f, 0.0f,
937 -0.707106781187f, -0.707106781187f, 0.0f,
938 0.707106781187f, -0.707106781187f, 0.0f,
939 0.707106781187f, 0.0f, -0.5f,
940 0.0f, 0.707106781187f, -0.5f,
941 -0.707106781187f, 0.0f, -0.5f,
942 0.0f, -0.707106781187f, -0.5f,
946 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
948 0.353553390594f, 0.353553390594f, 0.5f,
949 -0.353553390594f, 0.353553390594f, 0.5f,
950 -0.353553390594f, -0.353553390594f, 0.5f,
951 0.353553390594f, -0.353553390594f, 0.5f,
956 0.353553390594f, 0.353553390594f, -0.5f,
957 -0.353553390594f, 0.353553390594f, -0.5f,
958 -0.353553390594f, -0.353553390594f, -0.5f,
959 0.353553390594f, -0.353553390594f, -0.5f
963 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
978 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
980 /* -- Tetrahedron -- */
981 /* Magic Numbers: r0 = ( 1, 0, 0 )
982 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
983 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
984 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
985 * |r0| = |r1| = |r2| = |r3| = 1
986 * Distance between any two points is 2 sqrt(6) / 3
988 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
990 #define TETRAHEDRON_NUM_VERT 4
991 #define TETRAHEDRON_NUM_FACES 4
992 #define TETRAHEDRON_NUM_EDGE_PER_FACE 3
993 #define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
994 #define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
995 #define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
997 /* Vertex Coordinates */
998 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
1001 -0.333333333333f, 0.942809041582f, 0.0f,
1002 -0.333333333333f, -0.471404520791f, 0.816496580928f,
1003 -0.333333333333f, -0.471404520791f, -0.816496580928f
1005 /* Normal Vectors */
1006 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
1009 0.333333333333f, -0.942809041582f, 0.0f,
1010 0.333333333333f, 0.471404520791f, -0.816496580928f,
1011 0.333333333333f, 0.471404520791f, 0.816496580928f
1014 /* Vertex indices */
1015 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
1022 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
1024 /* -- Sierpinski Sponge -- */
1025 static unsigned int ipow (int x, unsigned int y)
1027 /* return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2); */
1036 return (y%2? x: 1) * ipow(x*x, y/2);
1041 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
1044 if ( numLevels == 0 )
1046 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
1049 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
1050 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
1052 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
1053 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
1055 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
1056 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
1057 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
1059 normals [outIdx ] = tetrahedron_n[normIdx ];
1060 normals [outIdx+1] = tetrahedron_n[normIdx+1];
1061 normals [outIdx+2] = tetrahedron_n[normIdx+2];
1065 else if ( numLevels > 0 )
1067 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
1068 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
1070 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
1073 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
1074 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
1075 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
1076 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
1081 /* -- Now the various non-polyhedra (shapes involving circles) -- */
1083 * Compute lookup table of cos and sin values forming a circle
1084 * (or half circle if halfCircle==TRUE)
1087 * It is the responsibility of the caller to free these tables
1088 * The size of the table is (n+1) to form a connected loop
1089 * The last entry is exactly the same as the first
1090 * The sign of n can be flipped to get the reverse loop
1092 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
1096 /* Table size, the sign of n flips the circle direction */
1097 const int size = abs(n);
1099 /* Determine the angle between samples */
1100 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
1102 /* Allocate memory for n samples, plus duplicate of first entry at the end */
1103 *sint = malloc(sizeof(GLfloat) * (size+1));
1104 *cost = malloc(sizeof(GLfloat) * (size+1));
1106 /* Bail out if memory allocation fails, fgError never returns */
1107 if (!(*sint) || !(*cost))
1111 fgError("Failed to allocate memory in fghCircleTable");
1114 /* Compute cos and sin around the circle */
1118 for (i=1; i<size; i++)
1120 (*sint)[i] = (GLfloat)sin(angle*i);
1121 (*cost)[i] = (GLfloat)cos(angle*i);
1127 (*sint)[size] = 0.0f; /* sin PI */
1128 (*cost)[size] = -1.0f; /* cos PI */
1132 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
1133 (*sint)[size] = (*sint)[0];
1134 (*cost)[size] = (*cost)[0];
1138 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
1141 int idx = 0; /* idx into vertex/normal buffer */
1144 /* Pre-computed circle */
1145 GLfloat *sint1,*cost1;
1146 GLfloat *sint2,*cost2;
1148 /* number of unique vertices */
1149 if (slices==0 || stacks<2)
1151 /* nothing to generate */
1155 *nVert = slices*(stacks-1)+2;
1156 if ((*nVert) > 65535)
1158 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1160 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1162 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
1164 /* precompute values on unit circle */
1165 fghCircleTable(&sint1,&cost1,-slices,FALSE);
1166 fghCircleTable(&sint2,&cost2, stacks,TRUE);
1168 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1169 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1170 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1171 if (!(*vertices) || !(*normals))
1175 fgError("Failed to allocate memory in fghGenerateSphere");
1179 (*vertices)[0] = 0.f;
1180 (*vertices)[1] = 0.f;
1181 (*vertices)[2] = radius;
1182 (*normals )[0] = 0.f;
1183 (*normals )[1] = 0.f;
1184 (*normals )[2] = 1.f;
1188 for( i=1; i<stacks; i++ )
1190 for(j=0; j<slices; j++, idx+=3)
1192 x = cost1[j]*sint2[i];
1193 y = sint1[j]*sint2[i];
1196 (*vertices)[idx ] = x*radius;
1197 (*vertices)[idx+1] = y*radius;
1198 (*vertices)[idx+2] = z*radius;
1199 (*normals )[idx ] = x;
1200 (*normals )[idx+1] = y;
1201 (*normals )[idx+2] = z;
1206 (*vertices)[idx ] = 0.f;
1207 (*vertices)[idx+1] = 0.f;
1208 (*vertices)[idx+2] = -radius;
1209 (*normals )[idx ] = 0.f;
1210 (*normals )[idx+1] = 0.f;
1211 (*normals )[idx+2] = -1.f;
1213 /* Done creating vertices, release sin and cos tables */
1220 void fghGenerateCone(
1221 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1222 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1226 int idx = 0; /* idx into vertex/normal buffer */
1228 /* Pre-computed circle */
1229 GLfloat *sint,*cost;
1231 /* Step in z and radius as stacks are drawn. */
1233 GLfloat r = (GLfloat)base;
1235 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1236 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1238 /* Scaling factors for vertex normals */
1239 const GLfloat cosn = (GLfloat) (height / sqrt( height * height + base * base ));
1240 const GLfloat sinn = (GLfloat) (base / sqrt( height * height + base * base ));
1244 /* number of unique vertices */
1245 if (slices==0 || stacks<1)
1247 /* nothing to generate */
1251 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1253 if ((*nVert) > 65535)
1255 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1257 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1259 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1261 /* Pre-computed circle */
1262 fghCircleTable(&sint,&cost,-slices,FALSE);
1264 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1265 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1266 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1267 if (!(*vertices) || !(*normals))
1271 fgError("Failed to allocate memory in fghGenerateCone");
1275 (*vertices)[0] = 0.f;
1276 (*vertices)[1] = 0.f;
1278 (*normals )[0] = 0.f;
1279 (*normals )[1] = 0.f;
1280 (*normals )[2] = -1.f;
1282 /* other on bottom (get normals right) */
1283 for (j=0; j<slices; j++, idx+=3)
1285 (*vertices)[idx ] = cost[j]*r;
1286 (*vertices)[idx+1] = sint[j]*r;
1287 (*vertices)[idx+2] = z;
1288 (*normals )[idx ] = 0.f;
1289 (*normals )[idx+1] = 0.f;
1290 (*normals )[idx+2] = -1.f;
1294 for (i=0; i<stacks+1; i++ )
1296 for (j=0; j<slices; j++, idx+=3)
1298 (*vertices)[idx ] = cost[j]*r;
1299 (*vertices)[idx+1] = sint[j]*r;
1300 (*vertices)[idx+2] = z;
1301 (*normals )[idx ] = cost[j]*cosn;
1302 (*normals )[idx+1] = sint[j]*cosn;
1303 (*normals )[idx+2] = sinn;
1310 /* Release sin and cos tables */
1315 void fghGenerateCylinder(
1316 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1317 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1321 int idx = 0; /* idx into vertex/normal buffer */
1323 /* Step in z as stacks are drawn. */
1324 GLfloat radf = (GLfloat)radius;
1326 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1328 /* Pre-computed circle */
1329 GLfloat *sint,*cost;
1331 /* number of unique vertices */
1332 if (slices==0 || stacks<1)
1334 /* nothing to generate */
1338 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1340 if ((*nVert) > 65535)
1342 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1344 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1346 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1348 /* Pre-computed circle */
1349 fghCircleTable(&sint,&cost,-slices,FALSE);
1351 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1352 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1353 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1354 if (!(*vertices) || !(*normals))
1358 fgError("Failed to allocate memory in fghGenerateCylinder");
1363 (*vertices)[0] = 0.f;
1364 (*vertices)[1] = 0.f;
1365 (*vertices)[2] = 0.f;
1366 (*normals )[0] = 0.f;
1367 (*normals )[1] = 0.f;
1368 (*normals )[2] = -1.f;
1370 /* other on top (get normals right) */
1371 for (j=0; j<slices; j++, idx+=3)
1373 (*vertices)[idx ] = cost[j]*radf;
1374 (*vertices)[idx+1] = sint[j]*radf;
1375 (*vertices)[idx+2] = z;
1376 (*normals )[idx ] = 0.f;
1377 (*normals )[idx+1] = 0.f;
1378 (*normals )[idx+2] = -1.f;
1382 for (i=0; i<stacks+1; i++ )
1384 for (j=0; j<slices; j++, idx+=3)
1386 (*vertices)[idx ] = cost[j]*radf;
1387 (*vertices)[idx+1] = sint[j]*radf;
1388 (*vertices)[idx+2] = z;
1389 (*normals )[idx ] = cost[j];
1390 (*normals )[idx+1] = sint[j];
1391 (*normals )[idx+2] = 0.f;
1397 /* other on bottom (get normals right) */
1399 for (j=0; j<slices; j++, idx+=3)
1401 (*vertices)[idx ] = cost[j]*radf;
1402 (*vertices)[idx+1] = sint[j]*radf;
1403 (*vertices)[idx+2] = z;
1404 (*normals )[idx ] = 0.f;
1405 (*normals )[idx+1] = 0.f;
1406 (*normals )[idx+2] = 1.f;
1410 (*vertices)[idx ] = 0.f;
1411 (*vertices)[idx+1] = 0.f;
1412 (*vertices)[idx+2] = height;
1413 (*normals )[idx ] = 0.f;
1414 (*normals )[idx+1] = 0.f;
1415 (*normals )[idx+2] = 1.f;
1417 /* Release sin and cos tables */
1422 void fghGenerateTorus(
1423 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1424 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1427 GLfloat iradius = (float)dInnerRadius;
1428 GLfloat oradius = (float)dOuterRadius;
1431 /* Pre-computed circle */
1432 GLfloat *spsi, *cpsi;
1433 GLfloat *sphi, *cphi;
1435 /* number of unique vertices */
1436 if (nSides<2 || nRings<2)
1438 /* nothing to generate */
1442 *nVert = nSides * nRings;
1444 if ((*nVert) > 65535)
1446 * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
1448 * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
1450 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1452 /* precompute values on unit circle */
1453 fghCircleTable(&spsi,&cpsi, nRings,FALSE);
1454 fghCircleTable(&sphi,&cphi,-nSides,FALSE);
1456 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1457 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1458 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1459 if (!(*vertices) || !(*normals))
1463 fgError("Failed to allocate memory in fghGenerateTorus");
1466 for( j=0; j<nRings; j++ )
1468 for( i=0; i<nSides; i++ )
1470 int offset = 3 * ( j * nSides + i ) ;
1472 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1473 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1474 (*vertices)[offset+2] = sphi[i] * iradius ;
1475 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1476 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1477 (*normals )[offset+2] = sphi[i] ;
1481 /* Release sin and cos tables */
1488 /* -- INTERNAL DRAWING functions --------------------------------------- */
1489 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1490 static void fgh##nameICaps( GLboolean useWireMode )\
1494 fgh##nameICaps##Generate();\
1495 name##Cached = GL_TRUE;\
1500 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1501 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1506 fghDrawGeometrySolid(name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ,\
1507 vertIdxs, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1510 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1511 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1513 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1520 cubeCached = GL_TRUE;
1525 /* Need to build new vertex list containing vertices for cube of different size */
1528 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1530 /* Bail out if memory allocation fails, fgError never returns */
1534 fgError("Failed to allocate memory in fghCube");
1537 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1538 vertices[i] = dSize*cube_verts[i];
1541 vertices = cube_verts;
1544 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1545 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1548 fghDrawGeometrySolid(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1549 cube_vertIdxs, 1, CUBE_VERT_PER_OBJ_TRI);
1552 /* cleanup allocated memory */
1556 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1557 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1558 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1559 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1560 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1562 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1566 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1567 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1568 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1572 /* Allocate memory */
1573 vertices = malloc(numVert*3 * sizeof(GLfloat));
1574 normals = malloc(numVert*3 * sizeof(GLfloat));
1575 /* Bail out if memory allocation fails, fgError never returns */
1576 if (!vertices || !normals)
1580 fgError("Failed to allocate memory in fghSierpinskiSponge");
1583 /* Generate elements */
1584 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1586 /* Draw and cleanup */
1588 fghDrawGeometryWire (vertices,normals,numVert,
1589 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1592 fghDrawGeometrySolid(vertices,normals,numVert,NULL,1,0);
1600 static void fghSphere( GLfloat radius, GLint slices, GLint stacks, GLboolean useWireMode )
1603 GLfloat *vertices, *normals;
1605 /* Generate vertices and normals */
1606 fghGenerateSphere(radius,slices,stacks,&vertices,&normals,&nVert);
1609 /* nothing to draw */
1614 GLushort *sliceIdx, *stackIdx;
1615 /* First, generate vertex index arrays for drawing with glDrawElements
1616 * We have a bunch of line_loops to draw for each stack, and a
1617 * bunch for each slice.
1620 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1621 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1622 if (!(stackIdx) || !(sliceIdx))
1626 fgError("Failed to allocate memory in fghSphere");
1629 /* generate for each stack */
1630 for (i=0,idx=0; i<stacks-1; i++)
1632 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1633 for (j=0; j<slices; j++, idx++)
1635 stackIdx[idx] = offset+j;
1639 /* generate for each slice */
1640 for (i=0,idx=0; i<slices; i++)
1642 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1643 sliceIdx[idx++] = 0; /* vertex on top */
1644 for (j=0; j<stacks-1; j++, idx++)
1646 sliceIdx[idx] = offset+j*slices;
1648 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1652 fghDrawGeometryWire(vertices,normals,nVert,
1653 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1654 stackIdx,stacks-1,slices);
1656 /* cleanup allocated memory */
1662 /* First, generate vertex index arrays for drawing with glDrawElements
1663 * All stacks, including top and bottom are covered with a triangle
1667 /* Create index vector */
1670 /* Allocate buffers for indices, bail out if memory allocation fails */
1671 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1675 fgError("Failed to allocate memory in fghSphere");
1679 for (j=0, idx=0; j<slices; j++, idx+=2)
1681 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1682 stripIdx[idx+1] = 0;
1684 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1685 stripIdx[idx+1] = 0;
1688 /* middle stacks: */
1689 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1690 for (i=0; i<stacks-2; i++, idx+=2)
1692 offset = 1+i*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1693 for (j=0; j<slices; j++, idx+=2)
1695 stripIdx[idx ] = offset+j+slices;
1696 stripIdx[idx+1] = offset+j;
1698 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1699 stripIdx[idx+1] = offset;
1703 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 */
1704 for (j=0; j<slices; j++, idx+=2)
1706 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1707 stripIdx[idx+1] = offset+j;
1709 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1710 stripIdx[idx+1] = offset;
1714 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks,(slices+1)*2);
1716 /* cleanup allocated memory */
1720 /* cleanup allocated memory */
1725 static void fghCone( GLfloat base, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1728 GLfloat *vertices, *normals;
1730 /* Generate vertices and normals */
1731 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1732 fghGenerateCone(base,height,slices,stacks,&vertices,&normals,&nVert);
1735 /* nothing to draw */
1740 GLushort *sliceIdx, *stackIdx;
1741 /* First, generate vertex index arrays for drawing with glDrawElements
1742 * We have a bunch of line_loops to draw for each stack, and a
1743 * bunch for each slice.
1746 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1747 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1748 if (!(stackIdx) || !(sliceIdx))
1752 fgError("Failed to allocate memory in fghCone");
1755 /* generate for each stack */
1756 for (i=0,idx=0; i<stacks; i++)
1758 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1759 for (j=0; j<slices; j++, idx++)
1761 stackIdx[idx] = offset+j;
1765 /* generate for each slice */
1766 for (i=0,idx=0; i<slices; i++)
1768 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1769 sliceIdx[idx++] = offset+slices;
1770 sliceIdx[idx++] = offset+(stacks+1)*slices;
1774 fghDrawGeometryWire(vertices,normals,nVert,
1775 sliceIdx,1,slices*2,GL_LINES,
1776 stackIdx,stacks,slices);
1778 /* cleanup allocated memory */
1784 /* First, generate vertex index arrays for drawing with glDrawElements
1785 * All stacks, including top and bottom are covered with a triangle
1789 /* Create index vector */
1792 /* Allocate buffers for indices, bail out if memory allocation fails */
1793 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1797 fgError("Failed to allocate memory in fghCone");
1801 for (j=0, idx=0; j<slices; j++, idx+=2)
1804 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1806 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1807 stripIdx[idx+1] = 1;
1810 /* middle stacks: */
1811 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1812 for (i=0; i<stacks; i++, idx+=2)
1814 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 */
1815 for (j=0; j<slices; j++, idx+=2)
1817 stripIdx[idx ] = offset+j;
1818 stripIdx[idx+1] = offset+j+slices;
1820 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1821 stripIdx[idx+1] = offset+slices;
1825 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+1,(slices+1)*2);
1827 /* cleanup allocated memory */
1831 /* cleanup allocated memory */
1836 static void fghCylinder( GLfloat radius, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1839 GLfloat *vertices, *normals;
1841 /* Generate vertices and normals */
1842 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1843 fghGenerateCylinder(radius,height,slices,stacks,&vertices,&normals,&nVert);
1846 /* nothing to draw */
1851 GLushort *sliceIdx, *stackIdx;
1852 /* First, generate vertex index arrays for drawing with glDrawElements
1853 * We have a bunch of line_loops to draw for each stack, and a
1854 * bunch for each slice.
1857 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1858 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1859 if (!(stackIdx) || !(sliceIdx))
1863 fgError("Failed to allocate memory in fghCylinder");
1866 /* generate for each stack */
1867 for (i=0,idx=0; i<stacks+1; i++)
1869 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1870 for (j=0; j<slices; j++, idx++)
1872 stackIdx[idx] = offset+j;
1876 /* generate for each slice */
1877 for (i=0,idx=0; i<slices; i++)
1879 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1880 sliceIdx[idx++] = offset+slices;
1881 sliceIdx[idx++] = offset+(stacks+1)*slices;
1885 fghDrawGeometryWire(vertices,normals,nVert,
1886 sliceIdx,1,slices*2,GL_LINES,
1887 stackIdx,stacks+1,slices);
1889 /* cleanup allocated memory */
1895 /* First, generate vertex index arrays for drawing with glDrawElements
1896 * All stacks, including top and bottom are covered with a triangle
1900 /* Create index vector */
1903 /* Allocate buffers for indices, bail out if memory allocation fails */
1904 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1908 fgError("Failed to allocate memory in fghCylinder");
1912 for (j=0, idx=0; j<slices; j++, idx+=2)
1915 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1917 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1918 stripIdx[idx+1] = 1;
1921 /* middle stacks: */
1922 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1923 for (i=0; i<stacks; i++, idx+=2)
1925 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 */
1926 for (j=0; j<slices; j++, idx+=2)
1928 stripIdx[idx ] = offset+j;
1929 stripIdx[idx+1] = offset+j+slices;
1931 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1932 stripIdx[idx+1] = offset+slices;
1936 offset = 1+(stacks+2)*slices;
1937 for (j=0; j<slices; j++, idx+=2)
1939 stripIdx[idx ] = offset+j;
1940 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1942 stripIdx[idx ] = offset;
1943 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1946 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,stacks+2,(slices+1)*2);
1948 /* cleanup allocated memory */
1952 /* cleanup allocated memory */
1957 static void fghTorus( GLfloat dInnerRadius, GLfloat dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1960 GLfloat *vertices, *normals;
1962 /* Generate vertices and normals */
1963 fghGenerateTorus(dInnerRadius,dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1966 /* nothing to draw */
1971 GLushort *sideIdx, *ringIdx;
1972 /* First, generate vertex index arrays for drawing with glDrawElements
1973 * We have a bunch of line_loops to draw each side, and a
1974 * bunch for each ring.
1977 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1978 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1979 if (!(ringIdx) || !(sideIdx))
1983 fgError("Failed to allocate memory in fghTorus");
1986 /* generate for each ring */
1987 for( j=0,idx=0; j<nRings; j++ )
1988 for( i=0; i<nSides; i++, idx++ )
1989 ringIdx[idx] = j * nSides + i;
1991 /* generate for each side */
1992 for( i=0,idx=0; i<nSides; i++ )
1993 for( j=0; j<nRings; j++, idx++ )
1994 sideIdx[idx] = j * nSides + i;
1997 fghDrawGeometryWire(vertices,normals,nVert,
1998 ringIdx,nRings,nSides,GL_LINE_LOOP,
1999 sideIdx,nSides,nRings);
2001 /* cleanup allocated memory */
2007 /* First, generate vertex index arrays for drawing with glDrawElements
2008 * All stacks, including top and bottom are covered with a triangle
2013 /* Allocate buffers for indices, bail out if memory allocation fails */
2014 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
2018 fgError("Failed to allocate memory in fghTorus");
2021 for( i=0, idx=0; i<nSides; i++ )
2027 for( j=0; j<nRings; j++, idx+=2 )
2029 int offset = j * nSides + i;
2030 stripIdx[idx ] = offset;
2031 stripIdx[idx+1] = offset + ioff;
2033 /* repeat first to close off shape */
2035 stripIdx[idx+1] = i + ioff;
2040 fghDrawGeometrySolid(vertices,normals,nVert,stripIdx,nSides,(nRings+1)*2);
2042 /* cleanup allocated memory */
2046 /* cleanup allocated memory */
2052 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
2056 * Draws a solid sphere
2058 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
2060 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
2061 fghSphere((GLfloat)radius, slices, stacks, FALSE );
2065 * Draws a wire sphere
2067 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
2069 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
2070 fghSphere((GLfloat)radius, slices, stacks, TRUE );
2075 * Draws a solid cone
2077 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
2079 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
2080 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, FALSE );
2086 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
2088 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
2089 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, TRUE );
2094 * Draws a solid cylinder
2096 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
2098 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
2099 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, FALSE );
2103 * Draws a wire cylinder
2105 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
2107 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
2108 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, TRUE );
2112 * Draws a wire torus
2114 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2116 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
2117 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, TRUE);
2121 * Draws a solid torus
2123 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2125 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
2126 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, FALSE);
2131 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
2132 /* Macro to generate interface functions */
2133 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
2134 void FGAPIENTRY glutWire##nameICaps( void )\
2136 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
2137 fgh##nameICaps( TRUE );\
2139 void FGAPIENTRY glutSolid##nameICaps( void )\
2141 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
2142 fgh##nameICaps( FALSE );\
2145 void FGAPIENTRY glutWireCube( double dSize )
2147 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
2148 fghCube( (GLfloat)dSize, TRUE );
2150 void FGAPIENTRY glutSolidCube( double dSize )
2152 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
2153 fghCube( (GLfloat)dSize, FALSE );
2156 DECLARE_SHAPE_INTERFACE(Dodecahedron)
2157 DECLARE_SHAPE_INTERFACE(Icosahedron)
2158 DECLARE_SHAPE_INTERFACE(Octahedron)
2159 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
2161 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
2163 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
2164 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
2166 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
2168 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
2169 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
2172 DECLARE_SHAPE_INTERFACE(Tetrahedron)
2175 /*** END OF FILE ***/