4 * Freeglut geometry rendering methods.
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Creation date: Fri Dec 3 1999
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <GL/freeglut.h>
29 #include "fg_internal.h"
34 * A note: We do not use the GLuint data type for vertex index arrays
35 * in this code as Open GL ES1 only supports GLushort. This affects the
36 * cylindrical objects only (Torus, Sphere, Cylinder and Cone) and limits
37 * their number of vertices to 65535 (2^16-1). Thats about 256*256
38 * subdivisions, which is sufficient for just about any usage case, so
39 * I am not going to worry about it for now.
40 * One could do compile time detection of the gluint type through CMake,
41 * but it is likely that we'll eventually move to runtime selection
42 * of OpenGL or GLES1/2, which would make that strategy useless...
45 /* declare for drawing using the different OpenGL versions here so we can
46 have a nice code order below */
47 #ifndef GL_ES_VERSION_2_0
48 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
49 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
50 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
52 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
53 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
55 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
56 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
57 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
58 GLint attribute_v_coord, GLint attribute_v_normal
60 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
61 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
62 GLint attribute_v_coord, GLint attribute_v_normal, GLint attribute_v_texture);
63 /* declare function for generating visualization of normals */
64 static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices);
65 #ifndef GL_ES_VERSION_2_0
66 static void fghDrawNormalVisualization11();
68 static void fghDrawNormalVisualization20(GLint attribute_v_coord);
71 * Explanation of the functions has to be separate for the polyhedra and
72 * the non-polyhedra (objects with a circular cross-section).
74 * - We have only implemented the five platonic solids and the rhomboid
75 * dodecahedron. If you need more types of polyhedra, please see
77 * - Solids are drawn by glDrawArrays if composed of triangular faces
78 * (the tetrahedron, octahedron, and icosahedron), or are first
79 * decomposed into triangles and then drawn by glDrawElements if its
80 * faces are squares or pentagons (cube, dodecahedron and rhombic
81 * dodecahedron) as some vertices are repeated in that case.
82 * - WireFrame drawing is done using a GL_LINE_LOOP per face, and thus
83 * issuing one draw call per face. glDrawArrays is always used as no
84 * triangle decomposition is needed to draw faces. We use the "first"
85 * parameter in glDrawArrays to go from face to face.
88 * - We have implemented the sphere, cylinder, cone and torus.
89 * - All shapes are characterized by two parameters: the number of
90 * subdivisions along two axes used to construct the shape's vertices
91 * (e.g. stacks and slices for the sphere).
92 * As different subdivisions are most suitable for different shapes,
93 * and are thus also named differently, I wont provide general comments
95 * - Solids are drawn using glDrawArrays and GL_TRIANGLE_STRIP. Each
96 * strip covers one revolution around one of the two subdivision axes
98 * - WireFrame drawing is done for the subdivisions along the two axes
99 * separately, usually using GL_LINE_LOOP. Vertex index arrays are
100 * built containing the vertices to be drawn for each loop, which are
101 * then drawn using multiple calls to glDrawElements. As the number of
102 * subdivisions along the two axes is not guaranteed to be equal, the
103 * vertex indices for e.g. stacks and slices are stored in separate
104 * arrays, which makes the input to the drawing function a bit clunky,
105 * but allows for the same drawing function to be used for all shapes.
110 * Draw geometric shape in wire mode (only edges)
113 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
114 * The vertex coordinate and normal buffers, and the number of entries in
117 * a vertex indices buffer, optional (never passed for the polyhedra)
118 * GLsizei numParts, GLsizei numVertPerPart
119 * polyhedra: number of faces, and the number of vertices for drawing
121 * non-polyhedra: number of edges to draw for first subdivision (not
122 * necessarily equal to number of subdivisions requested by user, e.g.
123 * as each subdivision is enclosed by two edges), and number of
124 * vertices for drawing each
125 * numParts * numVertPerPart gives the number of entries in the vertex
128 * vertex drawing mode (e.g. always GL_LINE_LOOP for polyhedra, varies
130 * GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
131 * non-polyhedra only: same as the above, but now for subdivisions along
132 * the other axis. Always drawn as GL_LINE_LOOP.
134 * Feel free to contribute better naming ;)
136 void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
137 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
138 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
141 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
142 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
144 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
145 /* User requested a 2.0 draw */
146 fghDrawGeometryWire20(vertices, normals, numVertices,
147 vertIdxs, numParts, numVertPerPart, vertexMode,
148 vertIdxs2, numParts2, numVertPerPart2,
149 attribute_v_coord, attribute_v_normal);
150 #ifndef GL_ES_VERSION_2_0
152 fghDrawGeometryWire11(vertices, normals,
153 vertIdxs, numParts, numVertPerPart, vertexMode,
154 vertIdxs2, numParts2, numVertPerPart2);
158 /* Draw the geometric shape with filled triangles
161 * GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices
162 * The vertex coordinate, normal and texture coordinate buffers, and the
163 * number of entries in those
165 * a vertex indices buffer, optional (not passed for the polyhedra with
167 * GLsizei numParts, GLsizei numVertPerPart
168 * polyhedra: not used for polyhedra with triangular faces
169 (numEdgePerFace==3), as each vertex+normal pair is drawn only once,
170 so no vertex indices are used.
171 Else, the shape was triangulated (DECOMPOSE_TO_TRIANGLE), leading to
172 reuse of some vertex+normal pairs, and thus the need to draw with
173 glDrawElements. numParts is always 1 in this case (we can draw the
174 whole object with one call to glDrawElements as the vertex index
175 array contains separate triangles), and numVertPerPart indicates
176 the number of vertex indices in the vertex array.
177 * non-polyhedra: number of parts (GL_TRIANGLE_STRIPs) to be drawn
178 separately (numParts calls to glDrawElements) to create the object.
179 numVertPerPart indicates the number of vertex indices to be
180 processed at each draw call.
181 * numParts * numVertPerPart gives the number of entries in the vertex
184 void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
185 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
187 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
188 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
189 GLint attribute_v_texture = fgStructure.CurrentWindow->Window.attribute_v_texture;
191 if (fgStructure.CurrentWindow->State.VisualizeNormals)
192 /* generate normals for each vertex to be drawn as well */
193 fghGenerateNormalVisualization(vertices, normals, numVertices);
195 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
197 /* User requested a 2.0 draw */
198 fghDrawGeometrySolid20(vertices, normals, textcs, numVertices,
199 vertIdxs, numParts, numVertIdxsPerPart,
200 attribute_v_coord, attribute_v_normal, attribute_v_texture);
202 if (fgStructure.CurrentWindow->State.VisualizeNormals)
203 /* draw normals for each vertex as well */
204 fghDrawNormalVisualization20(attribute_v_coord);
206 #ifndef GL_ES_VERSION_2_0
209 fghDrawGeometrySolid11(vertices, normals, textcs, numVertices,
210 vertIdxs, numParts, numVertIdxsPerPart);
212 if (fgStructure.CurrentWindow->State.VisualizeNormals)
213 /* draw normals for each vertex as well */
214 fghDrawNormalVisualization11();
221 /* Version for OpenGL (ES) 1.1 */
222 #ifndef GL_ES_VERSION_2_0
223 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
224 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
225 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
230 glEnableClientState(GL_VERTEX_ARRAY);
231 glEnableClientState(GL_NORMAL_ARRAY);
233 glVertexPointer(3, GL_FLOAT, 0, vertices);
234 glNormalPointer(GL_FLOAT, 0, normals);
238 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
239 for (i=0; i<numParts; i++)
240 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
242 for (i=0; i<numParts; i++)
243 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
246 for (i=0; i<numParts2; i++)
247 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
249 glDisableClientState(GL_VERTEX_ARRAY);
250 glDisableClientState(GL_NORMAL_ARRAY);
254 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
255 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
259 glEnableClientState(GL_VERTEX_ARRAY);
260 glEnableClientState(GL_NORMAL_ARRAY);
262 glVertexPointer(3, GL_FLOAT, 0, vertices);
263 glNormalPointer(GL_FLOAT, 0, normals);
267 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
268 glTexCoordPointer(2, GL_FLOAT, 0, textcs);
272 glDrawArrays(GL_TRIANGLES, 0, numVertices);
275 for (i=0; i<numParts; i++)
276 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
278 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
280 glDisableClientState(GL_VERTEX_ARRAY);
281 glDisableClientState(GL_NORMAL_ARRAY);
283 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
287 /* Version for OpenGL (ES) >= 2.0 */
288 static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
289 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
290 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
291 GLint attribute_v_coord, GLint attribute_v_normal)
293 GLuint vbo_coords = 0, vbo_normals = 0,
294 ibo_elements = 0, ibo_elements2 = 0;
295 GLsizei numVertIdxs = numParts * numVertPerPart;
296 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
299 if (numVertices > 0 && attribute_v_coord != -1) {
300 fghGenBuffers(1, &vbo_coords);
301 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
302 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
303 vertices, FGH_STATIC_DRAW);
306 if (numVertices > 0 && attribute_v_normal != -1) {
307 fghGenBuffers(1, &vbo_normals);
308 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
309 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
310 normals, FGH_STATIC_DRAW);
313 if (vertIdxs != NULL) {
314 fghGenBuffers(1, &ibo_elements);
315 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
316 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
317 vertIdxs, FGH_STATIC_DRAW);
318 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
321 if (vertIdxs2 != NULL) {
322 fghGenBuffers(1, &ibo_elements2);
323 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
324 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
325 vertIdxs2, FGH_STATIC_DRAW);
326 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
330 fghEnableVertexAttribArray(attribute_v_coord);
331 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
332 fghVertexAttribPointer(
333 attribute_v_coord, /* attribute */
334 3, /* number of elements per vertex, here (x,y,z) */
335 GL_FLOAT, /* the type of each element */
336 GL_FALSE, /* take our values as-is */
337 0, /* no extra data between each position */
338 0 /* offset of first element */
340 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
344 fghEnableVertexAttribArray(attribute_v_normal);
345 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
346 fghVertexAttribPointer(
347 attribute_v_normal, /* attribute */
348 3, /* number of elements per vertex, here (x,y,z) */
349 GL_FLOAT, /* the type of each element */
350 GL_FALSE, /* take our values as-is */
351 0, /* no extra data between each position */
352 0 /* offset of first element */
354 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
358 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
359 for (i=0; i<numParts; i++)
360 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
362 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
363 for (i=0; i<numParts; i++)
364 glDrawElements(vertexMode, numVertPerPart,
365 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
366 /* Clean existing bindings before clean-up */
367 /* Android showed instability otherwise */
368 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
372 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
373 for (i=0; i<numParts2; i++)
374 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
375 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
376 /* Clean existing bindings before clean-up */
377 /* Android showed instability otherwise */
378 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
382 fghDisableVertexAttribArray(attribute_v_coord);
383 if (vbo_normals != 0)
384 fghDisableVertexAttribArray(attribute_v_normal);
387 fghDeleteBuffers(1, &vbo_coords);
388 if (vbo_normals != 0)
389 fghDeleteBuffers(1, &vbo_normals);
390 if (ibo_elements != 0)
391 fghDeleteBuffers(1, &ibo_elements);
392 if (ibo_elements2 != 0)
393 fghDeleteBuffers(1, &ibo_elements2);
399 /* Version for OpenGL (ES) >= 2.0 */
400 static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
401 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
402 GLint attribute_v_coord, GLint attribute_v_normal, GLint attribute_v_texture)
404 GLuint vbo_coords = 0, vbo_normals = 0, vbo_textcs = 0, ibo_elements = 0;
405 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
408 if (numVertices > 0 && attribute_v_coord != -1) {
409 fghGenBuffers(1, &vbo_coords);
410 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
411 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
412 vertices, FGH_STATIC_DRAW);
413 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
416 if (numVertices > 0 && attribute_v_normal != -1) {
417 fghGenBuffers(1, &vbo_normals);
418 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
419 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
420 normals, FGH_STATIC_DRAW);
421 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
424 if (numVertices > 0 && attribute_v_texture != -1 && textcs) {
425 fghGenBuffers(1, &vbo_textcs);
426 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_textcs);
427 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 2 * sizeof(textcs[0]),
428 textcs, FGH_STATIC_DRAW);
429 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
432 if (vertIdxs != NULL) {
433 fghGenBuffers(1, &ibo_elements);
434 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
435 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
436 vertIdxs, FGH_STATIC_DRAW);
437 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
441 fghEnableVertexAttribArray(attribute_v_coord);
442 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
443 fghVertexAttribPointer(
444 attribute_v_coord, /* attribute */
445 3, /* number of elements per vertex, here (x,y,z) */
446 GL_FLOAT, /* the type of each element */
447 GL_FALSE, /* take our values as-is */
448 0, /* no extra data between each position */
449 0 /* offset of first element */
451 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
455 fghEnableVertexAttribArray(attribute_v_normal);
456 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
457 fghVertexAttribPointer(
458 attribute_v_normal, /* attribute */
459 3, /* number of elements per vertex, here (x,y,z) */
460 GL_FLOAT, /* the type of each element */
461 GL_FALSE, /* take our values as-is */
462 0, /* no extra data between each position */
463 0 /* offset of first element */
465 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
469 fghEnableVertexAttribArray(attribute_v_texture);
470 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_textcs);
471 fghVertexAttribPointer(
472 attribute_v_texture,/* attribute */
473 2, /* number of elements per vertex, here (s,t) */
474 GL_FLOAT, /* the type of each element */
475 GL_FALSE, /* take our values as-is */
476 0, /* no extra data between each position */
477 0 /* offset of first element */
479 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
482 if (vertIdxs == NULL) {
483 glDrawArrays(GL_TRIANGLES, 0, numVertices);
485 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
487 for (i=0; i<numParts; i++) {
488 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
491 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
493 /* Clean existing bindings before clean-up */
494 /* Android showed instability otherwise */
495 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
499 fghDisableVertexAttribArray(attribute_v_coord);
500 if (vbo_normals != 0)
501 fghDisableVertexAttribArray(attribute_v_normal);
503 fghDisableVertexAttribArray(attribute_v_texture);
506 fghDeleteBuffers(1, &vbo_coords);
507 if (vbo_normals != 0)
508 fghDeleteBuffers(1, &vbo_normals);
510 fghDeleteBuffers(1, &vbo_textcs);
511 if (ibo_elements != 0)
512 fghDeleteBuffers(1, &ibo_elements);
518 * Generate vertex indices for visualizing the normals.
519 * vertices are written into verticesForNormalVisualization.
520 * This must be freed by caller, we do the free at the
521 * end of fghDrawNormalVisualization11/fghDrawNormalVisualization20
523 static GLfloat *verticesForNormalVisualization;
524 static GLsizei numNormalVertices = 0;
525 static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices)
528 numNormalVertices = numVertices * 2;
529 verticesForNormalVisualization = malloc(numNormalVertices*3 * sizeof(GLfloat));
531 for (i=0,j=0; i<numNormalVertices*3/2; i+=3, j+=6)
533 verticesForNormalVisualization[j+0] = vertices[i+0];
534 verticesForNormalVisualization[j+1] = vertices[i+1];
535 verticesForNormalVisualization[j+2] = vertices[i+2];
536 verticesForNormalVisualization[j+3] = vertices[i+0] + normals[i+0]/4.f;
537 verticesForNormalVisualization[j+4] = vertices[i+1] + normals[i+1]/4.f;
538 verticesForNormalVisualization[j+5] = vertices[i+2] + normals[i+2]/4.f;
542 /* Version for OpenGL (ES) 1.1 */
543 #ifndef GL_ES_VERSION_2_0
544 static void fghDrawNormalVisualization11()
546 GLfloat currentColor[4];
547 /* Setup draw color: (1,1,1)-shape's color */
548 glGetFloatv(GL_CURRENT_COLOR,currentColor);
549 glColor4f(1-currentColor[0],1-currentColor[1],1-currentColor[2],currentColor[3]);
551 glEnableClientState(GL_VERTEX_ARRAY);
553 glVertexPointer(3, GL_FLOAT, 0, verticesForNormalVisualization);
554 glDrawArrays(GL_LINES, 0, numNormalVertices);
556 glDisableClientState(GL_VERTEX_ARRAY);
558 /* Done, free memory, reset color */
559 free(verticesForNormalVisualization);
560 glColor4f(currentColor[0],currentColor[1],currentColor[2],currentColor[3]);
564 /* Version for OpenGL (ES) >= 2.0 */
565 static void fghDrawNormalVisualization20(GLint attribute_v_coord)
567 GLuint vbo_coords = 0;
569 if (attribute_v_coord != -1) {
570 fghGenBuffers(1, &vbo_coords);
571 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
572 fghBufferData(FGH_ARRAY_BUFFER, numNormalVertices * 3 * sizeof(verticesForNormalVisualization[0]),
573 verticesForNormalVisualization, FGH_STATIC_DRAW);
578 fghEnableVertexAttribArray(attribute_v_coord);
579 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
580 fghVertexAttribPointer(
581 attribute_v_coord, /* attribute */
582 3, /* number of elements per vertex, here (x,y,z) */
583 GL_FLOAT, /* the type of each element */
584 GL_FALSE, /* take our values as-is */
585 0, /* no extra data between each position */
586 0 /* offset of first element */
588 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
591 glDrawArrays(GL_LINES, 0, numNormalVertices);
594 fghDisableVertexAttribArray(attribute_v_coord);
597 fghDeleteBuffers(1, &vbo_coords);
599 /* Done, free memory */
600 free(verticesForNormalVisualization);
604 * Generate all combinations of vertices and normals needed to draw object.
605 * Optional shape decomposition to triangles:
606 * We'll use glDrawElements to draw all shapes that are not naturally
607 * composed of triangles, so generate an index vector here, using the
608 * below sampling scheme.
609 * Be careful to keep winding of all triangles counter-clockwise,
610 * assuming that input has correct winding...
612 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
613 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
615 static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
617 int i,j,numEdgeIdxPerFace;
618 GLubyte *vertSamps = NULL;
619 switch (numEdgePerFace)
622 /* nothing to do here, we'll draw with glDrawArrays */
625 vertSamps = vert4Decomp;
626 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
629 vertSamps = vert5Decomp;
630 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
634 * Build array with vertices using vertex coordinates and vertex indices
635 * Do same for normals.
636 * Need to do this because of different normals at shared vertices.
638 for (i=0; i<numFaces; i++)
641 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
642 for (j=0; j<numEdgePerFace; j++)
644 int outIdx = i*numEdgePerFace*3+j*3;
645 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
647 vertOut[outIdx ] = vertices[vertIdx ];
648 vertOut[outIdx+1] = vertices[vertIdx+1];
649 vertOut[outIdx+2] = vertices[vertIdx+2];
651 normOut[outIdx ] = normals [normIdx ];
652 normOut[outIdx+1] = normals [normIdx+1];
653 normOut[outIdx+2] = normals [normIdx+2];
656 /* generate vertex indices for each face */
658 for (j=0; j<numEdgeIdxPerFace; j++)
659 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
663 static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
665 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
666 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
670 /* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
671 /* -- stuff that can be cached -- */
672 /* Cache of input to glDrawArrays or glDrawElements
673 * In general, we build arrays with all vertices or normals.
674 * We cant compress this and use glDrawElements as all combinations of
675 * vertices and normals are unique.
677 #define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
678 static GLboolean name##Cached = GL_FALSE;\
679 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
680 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
681 static void fgh##nameICaps##Generate()\
683 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
684 name##_v, name##_vi, name##_n,\
685 name##_verts, name##_norms);\
687 #define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
688 static GLboolean name##Cached = GL_FALSE;\
689 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
690 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
691 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
692 static void fgh##nameICaps##Generate()\
694 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
695 name##_v, name##_vi, name##_n,\
696 name##_verts, name##_norms, name##_vertIdxs);\
700 #define CUBE_NUM_VERT 8
701 #define CUBE_NUM_FACES 6
702 #define CUBE_NUM_EDGE_PER_FACE 4
703 #define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
704 #define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
705 #define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
706 /* Vertex Coordinates */
707 static GLfloat cube_v[CUBE_NUM_VERT*3] =
719 static GLfloat cube_n[CUBE_NUM_FACES*3] =
729 /* Vertex indices, as quads, before triangulation */
730 static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
739 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
741 /* -- Dodecahedron -- */
742 /* Magic Numbers: It is possible to create a dodecahedron by attaching two
743 * pentagons to each face of of a cube. The coordinates of the points are:
744 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
745 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
746 * x = 0.61803398875 and z = 1.61803398875.
748 #define DODECAHEDRON_NUM_VERT 20
749 #define DODECAHEDRON_NUM_FACES 12
750 #define DODECAHEDRON_NUM_EDGE_PER_FACE 5
751 #define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
752 #define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
753 #define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
754 /* Vertex Coordinates */
755 static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
757 0.0f, 1.61803398875f, 0.61803398875f,
759 -0.61803398875f, 0.0f, 1.61803398875f,
760 0.61803398875f, 0.0f, 1.61803398875f,
762 0.0f, 1.61803398875f, -0.61803398875f,
764 0.61803398875f, 0.0f, -1.61803398875f,
765 -0.61803398875f, 0.0f, -1.61803398875f,
766 - 1.0f, 1.0f, - 1.0f,
767 0.0f, -1.61803398875f, 0.61803398875f,
769 - 1.0f, - 1.0f, 1.0f,
770 0.0f, -1.61803398875f, -0.61803398875f,
771 - 1.0f, - 1.0f, - 1.0f,
772 1.0f, - 1.0f, - 1.0f,
773 1.61803398875f, -0.61803398875f, 0.0f,
774 1.61803398875f, 0.61803398875f, 0.0f,
775 -1.61803398875f, 0.61803398875f, 0.0f,
776 -1.61803398875f, -0.61803398875f, 0.0f
779 static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
781 0.0f, 0.525731112119f, 0.850650808354f,
782 0.0f, 0.525731112119f, -0.850650808354f,
783 0.0f, -0.525731112119f, 0.850650808354f,
784 0.0f, -0.525731112119f, -0.850650808354f,
786 0.850650808354f, 0.0f, 0.525731112119f,
787 -0.850650808354f, 0.0f, 0.525731112119f,
788 0.850650808354f, 0.0f, -0.525731112119f,
789 -0.850650808354f, 0.0f, -0.525731112119f,
791 0.525731112119f, 0.850650808354f, 0.0f,
792 0.525731112119f, -0.850650808354f, 0.0f,
793 -0.525731112119f, 0.850650808354f, 0.0f,
794 -0.525731112119f, -0.850650808354f, 0.0f,
798 static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
815 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
818 /* -- Icosahedron -- */
819 #define ICOSAHEDRON_NUM_VERT 12
820 #define ICOSAHEDRON_NUM_FACES 20
821 #define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
822 #define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
823 #define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
824 #define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
825 /* Vertex Coordinates */
826 static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
829 0.447213595500f, 0.894427191000f, 0.0f,
830 0.447213595500f, 0.276393202252f, 0.850650808354f,
831 0.447213595500f, -0.723606797748f, 0.525731112119f,
832 0.447213595500f, -0.723606797748f, -0.525731112119f,
833 0.447213595500f, 0.276393202252f, -0.850650808354f,
834 -0.447213595500f, -0.894427191000f, 0.0f,
835 -0.447213595500f, -0.276393202252f, 0.850650808354f,
836 -0.447213595500f, 0.723606797748f, 0.525731112119f,
837 -0.447213595500f, 0.723606797748f, -0.525731112119f,
838 -0.447213595500f, -0.276393202252f, -0.850650808354f,
842 * 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] ) ;
843 * 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] ) ;
844 * 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] ) ;
846 static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
848 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
849 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
850 0.760845213033849f, -0.581234022404097f, 0.0f,
851 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
852 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
853 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
854 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
855 0.179611190633958f, -0.940456403667806f, 0.0f,
856 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
857 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
858 -0.179611190633958f, 0.940456403667806f, 0.0f,
859 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
860 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
861 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
862 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
863 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
864 -0.760845213033849f, 0.581234022404097f, 0.0f,
865 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
866 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
867 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
871 static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
894 DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
896 /* -- Octahedron -- */
897 #define OCTAHEDRON_NUM_VERT 6
898 #define OCTAHEDRON_NUM_FACES 8
899 #define OCTAHEDRON_NUM_EDGE_PER_FACE 3
900 #define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
901 #define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
902 #define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
904 /* Vertex Coordinates */
905 static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
916 static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
918 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
919 0.577350269189f, 0.577350269189f,-0.577350269189f,
920 0.577350269189f,-0.577350269189f, 0.577350269189f,
921 0.577350269189f,-0.577350269189f,-0.577350269189f,
922 -0.577350269189f, 0.577350269189f, 0.577350269189f,
923 -0.577350269189f, 0.577350269189f,-0.577350269189f,
924 -0.577350269189f,-0.577350269189f, 0.577350269189f,
925 -0.577350269189f,-0.577350269189f,-0.577350269189f
930 static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
941 DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
943 /* -- RhombicDodecahedron -- */
944 #define RHOMBICDODECAHEDRON_NUM_VERT 14
945 #define RHOMBICDODECAHEDRON_NUM_FACES 12
946 #define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
947 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
948 #define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
949 #define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
951 /* Vertex Coordinates */
952 static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
955 0.707106781187f, 0.0f, 0.5f,
956 0.0f, 0.707106781187f, 0.5f,
957 -0.707106781187f, 0.0f, 0.5f,
958 0.0f, -0.707106781187f, 0.5f,
959 0.707106781187f, 0.707106781187f, 0.0f,
960 -0.707106781187f, 0.707106781187f, 0.0f,
961 -0.707106781187f, -0.707106781187f, 0.0f,
962 0.707106781187f, -0.707106781187f, 0.0f,
963 0.707106781187f, 0.0f, -0.5f,
964 0.0f, 0.707106781187f, -0.5f,
965 -0.707106781187f, 0.0f, -0.5f,
966 0.0f, -0.707106781187f, -0.5f,
970 static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
972 0.353553390594f, 0.353553390594f, 0.5f,
973 -0.353553390594f, 0.353553390594f, 0.5f,
974 -0.353553390594f, -0.353553390594f, 0.5f,
975 0.353553390594f, -0.353553390594f, 0.5f,
980 0.353553390594f, 0.353553390594f, -0.5f,
981 -0.353553390594f, 0.353553390594f, -0.5f,
982 -0.353553390594f, -0.353553390594f, -0.5f,
983 0.353553390594f, -0.353553390594f, -0.5f
987 static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
1002 DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1004 /* -- Tetrahedron -- */
1005 /* Magic Numbers: r0 = ( 1, 0, 0 )
1006 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
1007 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
1008 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
1009 * |r0| = |r1| = |r2| = |r3| = 1
1010 * Distance between any two points is 2 sqrt(6) / 3
1012 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
1014 #define TETRAHEDRON_NUM_VERT 4
1015 #define TETRAHEDRON_NUM_FACES 4
1016 #define TETRAHEDRON_NUM_EDGE_PER_FACE 3
1017 #define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
1018 #define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
1019 #define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
1021 /* Vertex Coordinates */
1022 static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
1025 -0.333333333333f, 0.942809041582f, 0.0f,
1026 -0.333333333333f, -0.471404520791f, 0.816496580928f,
1027 -0.333333333333f, -0.471404520791f, -0.816496580928f
1029 /* Normal Vectors */
1030 static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
1033 0.333333333333f, -0.942809041582f, 0.0f,
1034 0.333333333333f, 0.471404520791f, -0.816496580928f,
1035 0.333333333333f, 0.471404520791f, 0.816496580928f
1038 /* Vertex indices */
1039 static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
1046 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
1048 /* -- Sierpinski Sponge -- */
1049 static unsigned int ipow (int x, unsigned int y)
1051 /* return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2); */
1060 return (y%2? x: 1) * ipow(x*x, y/2);
1065 static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
1068 if ( numLevels == 0 )
1070 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
1073 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
1074 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
1076 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
1077 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
1079 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
1080 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
1081 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
1083 normals [outIdx ] = tetrahedron_n[normIdx ];
1084 normals [outIdx+1] = tetrahedron_n[normIdx+1];
1085 normals [outIdx+2] = tetrahedron_n[normIdx+2];
1089 else if ( numLevels > 0 )
1091 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
1092 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
1094 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
1097 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
1098 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
1099 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
1100 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
1105 /* -- Now the various non-polyhedra (shapes involving circles) -- */
1107 * Compute lookup table of cos and sin values forming a circle
1108 * (or half circle if halfCircle==TRUE)
1111 * It is the responsibility of the caller to free these tables
1112 * The size of the table is (n+1) to form a connected loop
1113 * The last entry is exactly the same as the first
1114 * The sign of n can be flipped to get the reverse loop
1116 static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
1120 /* Table size, the sign of n flips the circle direction */
1121 const int size = abs(n);
1123 /* Determine the angle between samples */
1124 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
1126 /* Allocate memory for n samples, plus duplicate of first entry at the end */
1127 *sint = malloc(sizeof(GLfloat) * (size+1));
1128 *cost = malloc(sizeof(GLfloat) * (size+1));
1130 /* Bail out if memory allocation fails, fgError never returns */
1131 if (!(*sint) || !(*cost))
1135 fgError("Failed to allocate memory in fghCircleTable");
1138 /* Compute cos and sin around the circle */
1142 for (i=1; i<size; i++)
1144 (*sint)[i] = (GLfloat)sin(angle*i);
1145 (*cost)[i] = (GLfloat)cos(angle*i);
1151 (*sint)[size] = 0.0f; /* sin PI */
1152 (*cost)[size] = -1.0f; /* cos PI */
1156 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
1157 (*sint)[size] = (*sint)[0];
1158 (*cost)[size] = (*cost)[0];
1162 static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
1165 int idx = 0; /* idx into vertex/normal buffer */
1168 /* Pre-computed circle */
1169 GLfloat *sint1,*cost1;
1170 GLfloat *sint2,*cost2;
1172 /* number of unique vertices */
1173 if (slices==0 || stacks<2)
1175 /* nothing to generate */
1179 *nVert = slices*(stacks-1)+2;
1180 if ((*nVert) > 65535)
1182 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1184 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
1186 /* precompute values on unit circle */
1187 fghCircleTable(&sint1,&cost1,-slices,GL_FALSE);
1188 fghCircleTable(&sint2,&cost2, stacks,GL_TRUE);
1190 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1191 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1192 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1193 if (!(*vertices) || !(*normals))
1197 fgError("Failed to allocate memory in fghGenerateSphere");
1201 (*vertices)[0] = 0.f;
1202 (*vertices)[1] = 0.f;
1203 (*vertices)[2] = radius;
1204 (*normals )[0] = 0.f;
1205 (*normals )[1] = 0.f;
1206 (*normals )[2] = 1.f;
1210 for( i=1; i<stacks; i++ )
1212 for(j=0; j<slices; j++, idx+=3)
1214 x = cost1[j]*sint2[i];
1215 y = sint1[j]*sint2[i];
1218 (*vertices)[idx ] = x*radius;
1219 (*vertices)[idx+1] = y*radius;
1220 (*vertices)[idx+2] = z*radius;
1221 (*normals )[idx ] = x;
1222 (*normals )[idx+1] = y;
1223 (*normals )[idx+2] = z;
1228 (*vertices)[idx ] = 0.f;
1229 (*vertices)[idx+1] = 0.f;
1230 (*vertices)[idx+2] = -radius;
1231 (*normals )[idx ] = 0.f;
1232 (*normals )[idx+1] = 0.f;
1233 (*normals )[idx+2] = -1.f;
1235 /* Done creating vertices, release sin and cos tables */
1242 void fghGenerateCone(
1243 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1244 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1248 int idx = 0; /* idx into vertex/normal buffer */
1250 /* Pre-computed circle */
1251 GLfloat *sint,*cost;
1253 /* Step in z and radius as stacks are drawn. */
1255 GLfloat r = (GLfloat)base;
1257 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1258 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1260 /* Scaling factors for vertex normals */
1261 const GLfloat cosn = (GLfloat) (height / sqrt( height * height + base * base ));
1262 const GLfloat sinn = (GLfloat) (base / sqrt( height * height + base * base ));
1266 /* number of unique vertices */
1267 if (slices==0 || stacks<1)
1269 /* nothing to generate */
1273 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1275 if ((*nVert) > 65535)
1277 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1279 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1281 /* Pre-computed circle */
1282 fghCircleTable(&sint,&cost,-slices,GL_FALSE);
1284 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1285 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1286 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1287 if (!(*vertices) || !(*normals))
1291 fgError("Failed to allocate memory in fghGenerateCone");
1295 (*vertices)[0] = 0.f;
1296 (*vertices)[1] = 0.f;
1298 (*normals )[0] = 0.f;
1299 (*normals )[1] = 0.f;
1300 (*normals )[2] = -1.f;
1302 /* other on bottom (get normals right) */
1303 for (j=0; j<slices; j++, idx+=3)
1305 (*vertices)[idx ] = cost[j]*r;
1306 (*vertices)[idx+1] = sint[j]*r;
1307 (*vertices)[idx+2] = z;
1308 (*normals )[idx ] = 0.f;
1309 (*normals )[idx+1] = 0.f;
1310 (*normals )[idx+2] = -1.f;
1314 for (i=0; i<stacks+1; i++ )
1316 for (j=0; j<slices; j++, idx+=3)
1318 (*vertices)[idx ] = cost[j]*r;
1319 (*vertices)[idx+1] = sint[j]*r;
1320 (*vertices)[idx+2] = z;
1321 (*normals )[idx ] = cost[j]*cosn;
1322 (*normals )[idx+1] = sint[j]*cosn;
1323 (*normals )[idx+2] = sinn;
1330 /* Release sin and cos tables */
1335 void fghGenerateCylinder(
1336 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1337 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1341 int idx = 0; /* idx into vertex/normal buffer */
1343 /* Step in z as stacks are drawn. */
1344 GLfloat radf = (GLfloat)radius;
1346 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1348 /* Pre-computed circle */
1349 GLfloat *sint,*cost;
1351 /* number of unique vertices */
1352 if (slices==0 || stacks<1)
1354 /* nothing to generate */
1358 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1360 if ((*nVert) > 65535)
1362 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1364 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1366 /* Pre-computed circle */
1367 fghCircleTable(&sint,&cost,-slices,GL_FALSE);
1369 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1370 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1371 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1372 if (!(*vertices) || !(*normals))
1376 fgError("Failed to allocate memory in fghGenerateCylinder");
1381 (*vertices)[0] = 0.f;
1382 (*vertices)[1] = 0.f;
1383 (*vertices)[2] = 0.f;
1384 (*normals )[0] = 0.f;
1385 (*normals )[1] = 0.f;
1386 (*normals )[2] = -1.f;
1388 /* other on top (get normals right) */
1389 for (j=0; j<slices; j++, idx+=3)
1391 (*vertices)[idx ] = cost[j]*radf;
1392 (*vertices)[idx+1] = sint[j]*radf;
1393 (*vertices)[idx+2] = z;
1394 (*normals )[idx ] = 0.f;
1395 (*normals )[idx+1] = 0.f;
1396 (*normals )[idx+2] = -1.f;
1400 for (i=0; i<stacks+1; i++ )
1402 for (j=0; j<slices; j++, idx+=3)
1404 (*vertices)[idx ] = cost[j]*radf;
1405 (*vertices)[idx+1] = sint[j]*radf;
1406 (*vertices)[idx+2] = z;
1407 (*normals )[idx ] = cost[j];
1408 (*normals )[idx+1] = sint[j];
1409 (*normals )[idx+2] = 0.f;
1415 /* other on bottom (get normals right) */
1417 for (j=0; j<slices; j++, idx+=3)
1419 (*vertices)[idx ] = cost[j]*radf;
1420 (*vertices)[idx+1] = sint[j]*radf;
1421 (*vertices)[idx+2] = z;
1422 (*normals )[idx ] = 0.f;
1423 (*normals )[idx+1] = 0.f;
1424 (*normals )[idx+2] = 1.f;
1428 (*vertices)[idx ] = 0.f;
1429 (*vertices)[idx+1] = 0.f;
1430 (*vertices)[idx+2] = height;
1431 (*normals )[idx ] = 0.f;
1432 (*normals )[idx+1] = 0.f;
1433 (*normals )[idx+2] = 1.f;
1435 /* Release sin and cos tables */
1440 void fghGenerateTorus(
1441 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1442 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1445 GLfloat iradius = (float)dInnerRadius;
1446 GLfloat oradius = (float)dOuterRadius;
1449 /* Pre-computed circle */
1450 GLfloat *spsi, *cpsi;
1451 GLfloat *sphi, *cphi;
1453 /* number of unique vertices */
1454 if (nSides<2 || nRings<2)
1456 /* nothing to generate */
1460 *nVert = nSides * nRings;
1462 if ((*nVert) > 65535)
1464 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1466 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1468 /* precompute values on unit circle */
1469 fghCircleTable(&spsi,&cpsi, nRings,GL_FALSE);
1470 fghCircleTable(&sphi,&cphi,-nSides,GL_FALSE);
1472 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1473 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1474 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1475 if (!(*vertices) || !(*normals))
1479 fgError("Failed to allocate memory in fghGenerateTorus");
1482 for( j=0; j<nRings; j++ )
1484 for( i=0; i<nSides; i++ )
1486 int offset = 3 * ( j * nSides + i ) ;
1488 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1489 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1490 (*vertices)[offset+2] = sphi[i] * iradius ;
1491 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1492 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1493 (*normals )[offset+2] = sphi[i] ;
1497 /* Release sin and cos tables */
1504 /* -- INTERNAL DRAWING functions --------------------------------------- */
1505 #define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1506 static void fgh##nameICaps( GLboolean useWireMode )\
1510 fgh##nameICaps##Generate();\
1511 name##Cached = GL_TRUE;\
1516 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1517 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1522 fghDrawGeometrySolid(name##_verts,name##_norms,NULL,nameCaps##_VERT_PER_OBJ,\
1523 vertIdxs, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1526 #define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1527 #define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1529 static void fghCube( GLfloat dSize, GLboolean useWireMode )
1536 cubeCached = GL_TRUE;
1541 /* Need to build new vertex list containing vertices for cube of different size */
1544 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1546 /* Bail out if memory allocation fails, fgError never returns */
1550 fgError("Failed to allocate memory in fghCube");
1553 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1554 vertices[i] = dSize*cube_verts[i];
1557 vertices = cube_verts;
1560 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1561 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1564 fghDrawGeometrySolid(vertices, cube_norms, NULL, CUBE_VERT_PER_OBJ,
1565 cube_vertIdxs, 1, CUBE_VERT_PER_OBJ_TRI);
1568 /* cleanup allocated memory */
1572 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1573 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1574 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1575 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1576 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1578 static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1582 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1583 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1584 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1588 /* Allocate memory */
1589 vertices = malloc(numVert*3 * sizeof(GLfloat));
1590 normals = malloc(numVert*3 * sizeof(GLfloat));
1591 /* Bail out if memory allocation fails, fgError never returns */
1592 if (!vertices || !normals)
1596 fgError("Failed to allocate memory in fghSierpinskiSponge");
1599 /* Generate elements */
1600 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1602 /* Draw and cleanup */
1604 fghDrawGeometryWire (vertices,normals,numVert,
1605 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1608 fghDrawGeometrySolid(vertices,normals,NULL,numVert,NULL,1,0);
1616 static void fghSphere( GLfloat radius, GLint slices, GLint stacks, GLboolean useWireMode )
1619 GLfloat *vertices, *normals;
1621 /* Generate vertices and normals */
1622 fghGenerateSphere(radius,slices,stacks,&vertices,&normals,&nVert);
1625 /* nothing to draw */
1630 GLushort *sliceIdx, *stackIdx;
1631 /* First, generate vertex index arrays for drawing with glDrawElements
1632 * We have a bunch of line_loops to draw for each stack, and a
1633 * bunch for each slice.
1636 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1637 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1638 if (!(stackIdx) || !(sliceIdx))
1642 fgError("Failed to allocate memory in fghSphere");
1645 /* generate for each stack */
1646 for (i=0,idx=0; i<stacks-1; i++)
1648 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1649 for (j=0; j<slices; j++, idx++)
1651 stackIdx[idx] = offset+j;
1655 /* generate for each slice */
1656 for (i=0,idx=0; i<slices; i++)
1658 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1659 sliceIdx[idx++] = 0; /* vertex on top */
1660 for (j=0; j<stacks-1; j++, idx++)
1662 sliceIdx[idx] = offset+j*slices;
1664 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1668 fghDrawGeometryWire(vertices,normals,nVert,
1669 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1670 stackIdx,stacks-1,slices);
1672 /* cleanup allocated memory */
1678 /* First, generate vertex index arrays for drawing with glDrawElements
1679 * All stacks, including top and bottom are covered with a triangle
1683 /* Create index vector */
1686 /* Allocate buffers for indices, bail out if memory allocation fails */
1687 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1691 fgError("Failed to allocate memory in fghSphere");
1695 for (j=0, idx=0; j<slices; j++, idx+=2)
1697 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1698 stripIdx[idx+1] = 0;
1700 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1701 stripIdx[idx+1] = 0;
1704 /* middle stacks: */
1705 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1706 for (i=0; i<stacks-2; i++, idx+=2)
1708 offset = 1+i*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1709 for (j=0; j<slices; j++, idx+=2)
1711 stripIdx[idx ] = offset+j+slices;
1712 stripIdx[idx+1] = offset+j;
1714 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1715 stripIdx[idx+1] = offset;
1719 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 */
1720 for (j=0; j<slices; j++, idx+=2)
1722 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1723 stripIdx[idx+1] = offset+j;
1725 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1726 stripIdx[idx+1] = offset;
1730 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,stacks,(slices+1)*2);
1732 /* cleanup allocated memory */
1736 /* cleanup allocated memory */
1741 static void fghCone( GLfloat base, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1744 GLfloat *vertices, *normals;
1746 /* Generate vertices and normals */
1747 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1748 fghGenerateCone(base,height,slices,stacks,&vertices,&normals,&nVert);
1751 /* nothing to draw */
1756 GLushort *sliceIdx, *stackIdx;
1757 /* First, generate vertex index arrays for drawing with glDrawElements
1758 * We have a bunch of line_loops to draw for each stack, and a
1759 * bunch for each slice.
1762 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1763 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1764 if (!(stackIdx) || !(sliceIdx))
1768 fgError("Failed to allocate memory in fghCone");
1771 /* generate for each stack */
1772 for (i=0,idx=0; i<stacks; i++)
1774 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1775 for (j=0; j<slices; j++, idx++)
1777 stackIdx[idx] = offset+j;
1781 /* generate for each slice */
1782 for (i=0,idx=0; i<slices; i++)
1784 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1785 sliceIdx[idx++] = offset+slices;
1786 sliceIdx[idx++] = offset+(stacks+1)*slices;
1790 fghDrawGeometryWire(vertices,normals,nVert,
1791 sliceIdx,1,slices*2,GL_LINES,
1792 stackIdx,stacks,slices);
1794 /* cleanup allocated memory */
1800 /* First, generate vertex index arrays for drawing with glDrawElements
1801 * All stacks, including top and bottom are covered with a triangle
1805 /* Create index vector */
1808 /* Allocate buffers for indices, bail out if memory allocation fails */
1809 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1813 fgError("Failed to allocate memory in fghCone");
1817 for (j=0, idx=0; j<slices; j++, idx+=2)
1820 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1822 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1823 stripIdx[idx+1] = 1;
1826 /* middle stacks: */
1827 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1828 for (i=0; i<stacks; i++, idx+=2)
1830 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 */
1831 for (j=0; j<slices; j++, idx+=2)
1833 stripIdx[idx ] = offset+j;
1834 stripIdx[idx+1] = offset+j+slices;
1836 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1837 stripIdx[idx+1] = offset+slices;
1841 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,stacks+1,(slices+1)*2);
1843 /* cleanup allocated memory */
1847 /* cleanup allocated memory */
1852 static void fghCylinder( GLfloat radius, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1855 GLfloat *vertices, *normals;
1857 /* Generate vertices and normals */
1858 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1859 fghGenerateCylinder(radius,height,slices,stacks,&vertices,&normals,&nVert);
1862 /* nothing to draw */
1867 GLushort *sliceIdx, *stackIdx;
1868 /* First, generate vertex index arrays for drawing with glDrawElements
1869 * We have a bunch of line_loops to draw for each stack, and a
1870 * bunch for each slice.
1873 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1874 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1875 if (!(stackIdx) || !(sliceIdx))
1879 fgError("Failed to allocate memory in fghCylinder");
1882 /* generate for each stack */
1883 for (i=0,idx=0; i<stacks+1; i++)
1885 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1886 for (j=0; j<slices; j++, idx++)
1888 stackIdx[idx] = offset+j;
1892 /* generate for each slice */
1893 for (i=0,idx=0; i<slices; i++)
1895 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1896 sliceIdx[idx++] = offset+slices;
1897 sliceIdx[idx++] = offset+(stacks+1)*slices;
1901 fghDrawGeometryWire(vertices,normals,nVert,
1902 sliceIdx,1,slices*2,GL_LINES,
1903 stackIdx,stacks+1,slices);
1905 /* cleanup allocated memory */
1911 /* First, generate vertex index arrays for drawing with glDrawElements
1912 * All stacks, including top and bottom are covered with a triangle
1916 /* Create index vector */
1919 /* Allocate buffers for indices, bail out if memory allocation fails */
1920 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1924 fgError("Failed to allocate memory in fghCylinder");
1928 for (j=0, idx=0; j<slices; j++, idx+=2)
1931 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1933 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1934 stripIdx[idx+1] = 1;
1937 /* middle stacks: */
1938 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1939 for (i=0; i<stacks; i++, idx+=2)
1941 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 */
1942 for (j=0; j<slices; j++, idx+=2)
1944 stripIdx[idx ] = offset+j;
1945 stripIdx[idx+1] = offset+j+slices;
1947 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1948 stripIdx[idx+1] = offset+slices;
1952 offset = 1+(stacks+2)*slices;
1953 for (j=0; j<slices; j++, idx+=2)
1955 stripIdx[idx ] = offset+j;
1956 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1958 stripIdx[idx ] = offset;
1959 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1962 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,stacks+2,(slices+1)*2);
1964 /* cleanup allocated memory */
1968 /* cleanup allocated memory */
1973 static void fghTorus( GLfloat dInnerRadius, GLfloat dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1976 GLfloat *vertices, *normals;
1978 /* Generate vertices and normals */
1979 fghGenerateTorus(dInnerRadius,dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1982 /* nothing to draw */
1987 GLushort *sideIdx, *ringIdx;
1988 /* First, generate vertex index arrays for drawing with glDrawElements
1989 * We have a bunch of line_loops to draw each side, and a
1990 * bunch for each ring.
1993 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1994 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1995 if (!(ringIdx) || !(sideIdx))
1999 fgError("Failed to allocate memory in fghTorus");
2002 /* generate for each ring */
2003 for( j=0,idx=0; j<nRings; j++ )
2004 for( i=0; i<nSides; i++, idx++ )
2005 ringIdx[idx] = j * nSides + i;
2007 /* generate for each side */
2008 for( i=0,idx=0; i<nSides; i++ )
2009 for( j=0; j<nRings; j++, idx++ )
2010 sideIdx[idx] = j * nSides + i;
2013 fghDrawGeometryWire(vertices,normals,nVert,
2014 ringIdx,nRings,nSides,GL_LINE_LOOP,
2015 sideIdx,nSides,nRings);
2017 /* cleanup allocated memory */
2023 /* First, generate vertex index arrays for drawing with glDrawElements
2024 * All stacks, including top and bottom are covered with a triangle
2029 /* Allocate buffers for indices, bail out if memory allocation fails */
2030 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
2034 fgError("Failed to allocate memory in fghTorus");
2037 for( i=0, idx=0; i<nSides; i++ )
2043 for( j=0; j<nRings; j++, idx+=2 )
2045 int offset = j * nSides + i;
2046 stripIdx[idx ] = offset;
2047 stripIdx[idx+1] = offset + ioff;
2049 /* repeat first to close off shape */
2051 stripIdx[idx+1] = i + ioff;
2056 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,nSides,(nRings+1)*2);
2058 /* cleanup allocated memory */
2062 /* cleanup allocated memory */
2068 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
2072 * Draws a solid sphere
2074 void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
2076 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
2077 fghSphere((GLfloat)radius, slices, stacks, GL_FALSE );
2081 * Draws a wire sphere
2083 void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
2085 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
2086 fghSphere((GLfloat)radius, slices, stacks, GL_TRUE );
2091 * Draws a solid cone
2093 void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
2095 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
2096 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, GL_FALSE );
2102 void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
2104 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
2105 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, GL_TRUE );
2110 * Draws a solid cylinder
2112 void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
2114 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
2115 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, GL_FALSE );
2119 * Draws a wire cylinder
2121 void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
2123 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
2124 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, GL_TRUE );
2128 * Draws a wire torus
2130 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2132 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
2133 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, GL_TRUE);
2137 * Draws a solid torus
2139 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2141 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
2142 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, GL_FALSE);
2147 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
2148 /* Macro to generate interface functions */
2149 #define DECLARE_SHAPE_INTERFACE(nameICaps)\
2150 void FGAPIENTRY glutWire##nameICaps( void )\
2152 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
2153 fgh##nameICaps( GL_TRUE );\
2155 void FGAPIENTRY glutSolid##nameICaps( void )\
2157 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
2158 fgh##nameICaps( GL_FALSE );\
2161 void FGAPIENTRY glutWireCube( double dSize )
2163 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
2164 fghCube( (GLfloat)dSize, GL_TRUE );
2166 void FGAPIENTRY glutSolidCube( double dSize )
2168 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
2169 fghCube( (GLfloat)dSize, GL_FALSE );
2172 DECLARE_SHAPE_INTERFACE(Dodecahedron)
2173 DECLARE_SHAPE_INTERFACE(Icosahedron)
2174 DECLARE_SHAPE_INTERFACE(Octahedron)
2175 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
2177 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
2179 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
2180 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, GL_TRUE );
2182 void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
2184 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
2185 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, GL_FALSE );
2188 DECLARE_SHAPE_INTERFACE(Tetrahedron)
2191 /*** END OF FILE ***/