1/*
2 * fg_geometry.c
3 *
4 * Freeglut geometry rendering methods.
5 *
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
9 *
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:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
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.
26 */
27
28#include <GL/freeglut.h>
29#include "fg_internal.h"
30#include "fg_gl2.h"
31#include <math.h>
32
33/*
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...
43 */
44
45/* declare for drawing using the different OpenGL versions here so we can
46 have a nice code order below */
47static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
48 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
49 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
50 );
51static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
52 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
53static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
54 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
55 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
56 GLint attribute_v_coord, GLint attribute_v_normal
57 );
58static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
59 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
60 GLint attribute_v_coord, GLint attribute_v_normal, GLint attribute_v_texture);
61/* declare function for generating visualization of normals */
62static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices);
63static void fghDrawNormalVisualization11();
64static void fghDrawNormalVisualization20(GLint attribute_v_coord);
65
66/* Drawing geometry:
67 * Explanation of the functions has to be separate for the polyhedra and
68 * the non-polyhedra (objects with a circular cross-section).
69 * Polyhedra:
70 * - We have only implemented the five platonic solids and the rhomboid
71 * dodecahedron. If you need more types of polyhedra, please see
72 * CPolyhedron in MRPT
73 * - Solids are drawn by glDrawArrays if composed of triangular faces
74 * (the tetrahedron, octahedron, and icosahedron), or are first
75 * decomposed into triangles and then drawn by glDrawElements if its
76 * faces are squares or pentagons (cube, dodecahedron and rhombic
77 * dodecahedron) as some vertices are repeated in that case.
78 * - WireFrame drawing is done using a GL_LINE_LOOP per face, and thus
79 * issuing one draw call per face. glDrawArrays is always used as no
80 * triangle decomposition is needed to draw faces. We use the "first"
81 * parameter in glDrawArrays to go from face to face.
82 *
83 * Non-polyhedra:
84 * - We have implemented the sphere, cylinder, cone and torus.
85 * - All shapes are characterized by two parameters: the number of
86 * subdivisions along two axes used to construct the shape's vertices
87 * (e.g. stacks and slices for the sphere).
88 * As different subdivisions are most suitable for different shapes,
89 * and are thus also named differently, I wont provide general comments
90 * on them here.
91 * - Solids are drawn using glDrawArrays and GL_TRIANGLE_STRIP. Each
92 * strip covers one revolution around one of the two subdivision axes
93 * of the shape.
94 * - WireFrame drawing is done for the subdivisions along the two axes
95 * separately, usually using GL_LINE_LOOP. Vertex index arrays are
96 * built containing the vertices to be drawn for each loop, which are
97 * then drawn using multiple calls to glDrawElements. As the number of
98 * subdivisions along the two axes is not guaranteed to be equal, the
99 * vertex indices for e.g. stacks and slices are stored in separate
100 * arrays, which makes the input to the drawing function a bit clunky,
101 * but allows for the same drawing function to be used for all shapes.
102 */
103
104
105/**
106 * Draw geometric shape in wire mode (only edges)
107 *
108 * Arguments:
109 * GLfloat *vertices, GLfloat *normals, GLsizei numVertices
110 * The vertex coordinate and normal buffers, and the number of entries in
111 * those
112 * GLushort *vertIdxs
113 * a vertex indices buffer, optional (never passed for the polyhedra)
114 * GLsizei numParts, GLsizei numVertPerPart
115 * polyhedra: number of faces, and the number of vertices for drawing
116 * each face
117 * non-polyhedra: number of edges to draw for first subdivision (not
118 * necessarily equal to number of subdivisions requested by user, e.g.
119 * as each subdivision is enclosed by two edges), and number of
120 * vertices for drawing each
121 * numParts * numVertPerPart gives the number of entries in the vertex
122 * array vertIdxs
123 * GLenum vertexMode
124 * vertex drawing mode (e.g. always GL_LINE_LOOP for polyhedra, varies
125 * for others)
126 * GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
127 * non-polyhedra only: same as the above, but now for subdivisions along
128 * the other axis. Always drawn as GL_LINE_LOOP.
129 *
130 * Feel free to contribute better naming ;)
131 */
132void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
133 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
134 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
135 )
136{
137 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
138 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
139
140 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
141 /* User requested a 2.0 draw */
142 fghDrawGeometryWire20(vertices, normals, numVertices,
143 vertIdxs, numParts, numVertPerPart, vertexMode,
144 vertIdxs2, numParts2, numVertPerPart2,
145 attribute_v_coord, attribute_v_normal);
146 else
147 fghDrawGeometryWire11(vertices, normals,
148 vertIdxs, numParts, numVertPerPart, vertexMode,
149 vertIdxs2, numParts2, numVertPerPart2);
150}
151
152/* Draw the geometric shape with filled triangles
153 *
154 * Arguments:
155 * GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices
156 * The vertex coordinate, normal and texture coordinate buffers, and the
157 * number of entries in those
158 * GLushort *vertIdxs
159 * a vertex indices buffer, optional (not passed for the polyhedra with
160 * triangular faces)
161 * GLsizei numParts, GLsizei numVertPerPart
162 * polyhedra: not used for polyhedra with triangular faces
163 (numEdgePerFace==3), as each vertex+normal pair is drawn only once,
164 so no vertex indices are used.
165 Else, the shape was triangulated (DECOMPOSE_TO_TRIANGLE), leading to
166 reuse of some vertex+normal pairs, and thus the need to draw with
167 glDrawElements. numParts is always 1 in this case (we can draw the
168 whole object with one call to glDrawElements as the vertex index
169 array contains separate triangles), and numVertPerPart indicates
170 the number of vertex indices in the vertex array.
171 * non-polyhedra: number of parts (GL_TRIANGLE_STRIPs) to be drawn
172 separately (numParts calls to glDrawElements) to create the object.
173 numVertPerPart indicates the number of vertex indices to be
174 processed at each draw call.
175 * numParts * numVertPerPart gives the number of entries in the vertex
176 * array vertIdxs
177 */
178void fghDrawGeometrySolid(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
179 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
180{
181 GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
182 GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
183 GLint attribute_v_texture = fgStructure.CurrentWindow->Window.attribute_v_texture;
184
185 if (fgStructure.CurrentWindow->State.VisualizeNormals)
186 /* generate normals for each vertex to be drawn as well */
187 fghGenerateNormalVisualization(vertices, normals, numVertices);
188
189 if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
190 {
191 /* User requested a 2.0 draw */
192 fghDrawGeometrySolid20(vertices, normals, textcs, numVertices,
193 vertIdxs, numParts, numVertIdxsPerPart,
194 attribute_v_coord, attribute_v_normal, attribute_v_texture);
195
196 if (fgStructure.CurrentWindow->State.VisualizeNormals)
197 /* draw normals for each vertex as well */
198 fghDrawNormalVisualization20(attribute_v_coord);
199 }
200 else
201 {
202 fghDrawGeometrySolid11(vertices, normals, textcs, numVertices,
203 vertIdxs, numParts, numVertIdxsPerPart);
204
205 if (fgStructure.CurrentWindow->State.VisualizeNormals)
206 /* draw normals for each vertex as well */
207 fghDrawNormalVisualization11();
208 }
209}
210
211
212
213/* Version for OpenGL (ES) 1.1 */
214static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
215 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
216 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
217 )
218{
219 int i;
220
221 glEnableClientState(GL_VERTEX_ARRAY);
222 glEnableClientState(GL_NORMAL_ARRAY);
223
224 glVertexPointer(3, GL_FLOAT, 0, vertices);
225 glNormalPointer(GL_FLOAT, 0, normals);
226
227
228 if (!vertIdxs)
229 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
230 for (i=0; i<numParts; i++)
231 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
232 else
233 for (i=0; i<numParts; i++)
234 glDrawElements(vertexMode,numVertPerPart,GL_UNSIGNED_SHORT,vertIdxs+i*numVertPerPart);
235
236 if (vertIdxs2)
237 for (i=0; i<numParts2; i++)
238 glDrawElements(GL_LINE_LOOP,numVertPerPart2,GL_UNSIGNED_SHORT,vertIdxs2+i*numVertPerPart2);
239
240 glDisableClientState(GL_VERTEX_ARRAY);
241 glDisableClientState(GL_NORMAL_ARRAY);
242}
243
244
245static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
246 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
247{
248 int i;
249
250 glEnableClientState(GL_VERTEX_ARRAY);
251 glEnableClientState(GL_NORMAL_ARRAY);
252
253 glVertexPointer(3, GL_FLOAT, 0, vertices);
254 glNormalPointer(GL_FLOAT, 0, normals);
255
256 if (textcs)
257 {
258 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
259 glTexCoordPointer(2, GL_FLOAT, 0, textcs);
260 }
261
262 if (!vertIdxs)
263 glDrawArrays(GL_TRIANGLES, 0, numVertices);
264 else
265 if (numParts>1)
266 for (i=0; i<numParts; i++)
267 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs+i*numVertIdxsPerPart);
268 else
269 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, vertIdxs);
270
271 glDisableClientState(GL_VERTEX_ARRAY);
272 glDisableClientState(GL_NORMAL_ARRAY);
273 if (textcs)
274 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
275}
276
277/* Version for OpenGL (ES) >= 2.0 */
278static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
279 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
280 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
281 GLint attribute_v_coord, GLint attribute_v_normal)
282{
283 GLuint vbo_coords = 0, vbo_normals = 0,
284 ibo_elements = 0, ibo_elements2 = 0;
285 GLsizei numVertIdxs = numParts * numVertPerPart;
286 GLsizei numVertIdxs2 = numParts2 * numVertPerPart2;
287 int i;
288
289 if (numVertices > 0 && attribute_v_coord != -1) {
290 fghGenBuffers(1, &vbo_coords);
291 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
292 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
293 vertices, FGH_STATIC_DRAW);
294 }
295
296 if (numVertices > 0 && attribute_v_normal != -1) {
297 fghGenBuffers(1, &vbo_normals);
298 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
299 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
300 normals, FGH_STATIC_DRAW);
301 }
302
303 if (vertIdxs != NULL) {
304 fghGenBuffers(1, &ibo_elements);
305 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
306 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
307 vertIdxs, FGH_STATIC_DRAW);
308 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
309 }
310
311 if (vertIdxs2 != NULL) {
312 fghGenBuffers(1, &ibo_elements2);
313 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
314 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs2 * sizeof(vertIdxs2[0]),
315 vertIdxs2, FGH_STATIC_DRAW);
316 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
317 }
318
319 if (vbo_coords) {
320 fghEnableVertexAttribArray(attribute_v_coord);
321 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
322 fghVertexAttribPointer(
323 attribute_v_coord, /* attribute */
324 3, /* number of elements per vertex, here (x,y,z) */
325 GL_FLOAT, /* the type of each element */
326 GL_FALSE, /* take our values as-is */
327 0, /* no extra data between each position */
328 0 /* offset of first element */
329 );
330 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
331 }
332
333 if (vbo_normals) {
334 fghEnableVertexAttribArray(attribute_v_normal);
335 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
336 fghVertexAttribPointer(
337 attribute_v_normal, /* attribute */
338 3, /* number of elements per vertex, here (x,y,z) */
339 GL_FLOAT, /* the type of each element */
340 GL_FALSE, /* take our values as-is */
341 0, /* no extra data between each position */
342 0 /* offset of first element */
343 );
344 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
345 }
346
347 if (!vertIdxs) {
348 /* Draw per face (TODO: could use glMultiDrawArrays if available) */
349 for (i=0; i<numParts; i++)
350 glDrawArrays(vertexMode, i*numVertPerPart, numVertPerPart);
351 } else {
352 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
353 for (i=0; i<numParts; i++)
354 glDrawElements(vertexMode, numVertPerPart,
355 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertPerPart));
356 /* Clean existing bindings before clean-up */
357 /* Android showed instability otherwise */
358 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
359 }
360
361 if (vertIdxs2) {
362 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements2);
363 for (i=0; i<numParts2; i++)
364 glDrawElements(GL_LINE_LOOP, numVertPerPart2,
365 GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs2[0])*i*numVertPerPart2));
366 /* Clean existing bindings before clean-up */
367 /* Android showed instability otherwise */
368 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
369 }
370
371 if (vbo_coords != 0)
372 fghDisableVertexAttribArray(attribute_v_coord);
373 if (vbo_normals != 0)
374 fghDisableVertexAttribArray(attribute_v_normal);
375
376 if (vbo_coords != 0)
377 fghDeleteBuffers(1, &vbo_coords);
378 if (vbo_normals != 0)
379 fghDeleteBuffers(1, &vbo_normals);
380 if (ibo_elements != 0)
381 fghDeleteBuffers(1, &ibo_elements);
382 if (ibo_elements2 != 0)
383 fghDeleteBuffers(1, &ibo_elements2);
384}
385
386
387
388
389/* Version for OpenGL (ES) >= 2.0 */
390static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices,
391 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
392 GLint attribute_v_coord, GLint attribute_v_normal, GLint attribute_v_texture)
393{
394 GLuint vbo_coords = 0, vbo_normals = 0, vbo_textcs = 0, ibo_elements = 0;
395 GLsizei numVertIdxs = numParts * numVertIdxsPerPart;
396 int i;
397
398 if (numVertices > 0 && attribute_v_coord != -1) {
399 fghGenBuffers(1, &vbo_coords);
400 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
401 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(vertices[0]),
402 vertices, FGH_STATIC_DRAW);
403 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
404 }
405
406 if (numVertices > 0 && attribute_v_normal != -1) {
407 fghGenBuffers(1, &vbo_normals);
408 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
409 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 3 * sizeof(normals[0]),
410 normals, FGH_STATIC_DRAW);
411 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
412 }
413
414 if (numVertices > 0 && attribute_v_texture != -1 && textcs) {
415 fghGenBuffers(1, &vbo_textcs);
416 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_textcs);
417 fghBufferData(FGH_ARRAY_BUFFER, numVertices * 2 * sizeof(textcs[0]),
418 textcs, FGH_STATIC_DRAW);
419 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
420 }
421
422 if (vertIdxs != NULL) {
423 fghGenBuffers(1, &ibo_elements);
424 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
425 fghBufferData(FGH_ELEMENT_ARRAY_BUFFER, numVertIdxs * sizeof(vertIdxs[0]),
426 vertIdxs, FGH_STATIC_DRAW);
427 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
428 }
429
430 if (vbo_coords) {
431 fghEnableVertexAttribArray(attribute_v_coord);
432 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
433 fghVertexAttribPointer(
434 attribute_v_coord, /* attribute */
435 3, /* number of elements per vertex, here (x,y,z) */
436 GL_FLOAT, /* the type of each element */
437 GL_FALSE, /* take our values as-is */
438 0, /* no extra data between each position */
439 0 /* offset of first element */
440 );
441 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
442 };
443
444 if (vbo_normals) {
445 fghEnableVertexAttribArray(attribute_v_normal);
446 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_normals);
447 fghVertexAttribPointer(
448 attribute_v_normal, /* attribute */
449 3, /* number of elements per vertex, here (x,y,z) */
450 GL_FLOAT, /* the type of each element */
451 GL_FALSE, /* take our values as-is */
452 0, /* no extra data between each position */
453 0 /* offset of first element */
454 );
455 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
456 };
457
458 if (vbo_textcs) {
459 fghEnableVertexAttribArray(attribute_v_texture);
460 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_textcs);
461 fghVertexAttribPointer(
462 attribute_v_texture,/* attribute */
463 2, /* number of elements per vertex, here (s,t) */
464 GL_FLOAT, /* the type of each element */
465 GL_FALSE, /* take our values as-is */
466 0, /* no extra data between each position */
467 0 /* offset of first element */
468 );
469 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
470 };
471
472 if (vertIdxs == NULL) {
473 glDrawArrays(GL_TRIANGLES, 0, numVertices);
474 } else {
475 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, ibo_elements);
476 if (numParts>1) {
477 for (i=0; i<numParts; i++) {
478 glDrawElements(GL_TRIANGLE_STRIP, numVertIdxsPerPart, GL_UNSIGNED_SHORT, (GLvoid*)(sizeof(vertIdxs[0])*i*numVertIdxsPerPart));
479 }
480 } else {
481 glDrawElements(GL_TRIANGLES, numVertIdxsPerPart, GL_UNSIGNED_SHORT, 0);
482 }
483 /* Clean existing bindings before clean-up */
484 /* Android showed instability otherwise */
485 fghBindBuffer(FGH_ELEMENT_ARRAY_BUFFER, 0);
486 }
487
488 if (vbo_coords != 0)
489 fghDisableVertexAttribArray(attribute_v_coord);
490 if (vbo_normals != 0)
491 fghDisableVertexAttribArray(attribute_v_normal);
492 if (vbo_textcs != 0)
493 fghDisableVertexAttribArray(attribute_v_texture);
494
495 if (vbo_coords != 0)
496 fghDeleteBuffers(1, &vbo_coords);
497 if (vbo_normals != 0)
498 fghDeleteBuffers(1, &vbo_normals);
499 if (vbo_textcs != 0)
500 fghDeleteBuffers(1, &vbo_textcs);
501 if (ibo_elements != 0)
502 fghDeleteBuffers(1, &ibo_elements);
503}
504
505
506
507/**
508 * Generate vertex indices for visualizing the normals.
509 * vertices are written into verticesForNormalVisualization.
510 * This must be freed by caller, we do the free at the
511 * end of fghDrawNormalVisualization11/fghDrawNormalVisualization20
512 */
513static GLfloat *verticesForNormalVisualization;
514static GLsizei numNormalVertices = 0;
515static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices)
516{
517 int i,j;
518 numNormalVertices = numVertices * 2;
519 verticesForNormalVisualization = malloc(numNormalVertices*3 * sizeof(GLfloat));
520
521 for (i=0,j=0; i<numNormalVertices*3/2; i+=3, j+=6)
522 {
523 verticesForNormalVisualization[j+0] = vertices[i+0];
524 verticesForNormalVisualization[j+1] = vertices[i+1];
525 verticesForNormalVisualization[j+2] = vertices[i+2];
526 verticesForNormalVisualization[j+3] = vertices[i+0] + normals[i+0]/4.f;
527 verticesForNormalVisualization[j+4] = vertices[i+1] + normals[i+1]/4.f;
528 verticesForNormalVisualization[j+5] = vertices[i+2] + normals[i+2]/4.f;
529 }
530}
531
532/* Version for OpenGL (ES) 1.1 */
533static void fghDrawNormalVisualization11()
534{
535 GLfloat currentColor[4];
536 /* Setup draw color: (1,1,1)-shape's color */
537 glGetFloatv(GL_CURRENT_COLOR,currentColor);
538 glColor4f(1-currentColor[0],1-currentColor[1],1-currentColor[2],currentColor[3]);
539
540 glEnableClientState(GL_VERTEX_ARRAY);
541
542 glVertexPointer(3, GL_FLOAT, 0, verticesForNormalVisualization);
543 glDrawArrays(GL_LINES, 0, numNormalVertices);
544
545 glDisableClientState(GL_VERTEX_ARRAY);
546
547 /* Done, free memory, reset color */
548 free(verticesForNormalVisualization);
549 glColor4f(currentColor[0],currentColor[1],currentColor[2],currentColor[3]);
550}
551
552/* Version for OpenGL (ES) >= 2.0 */
553static void fghDrawNormalVisualization20(GLint attribute_v_coord)
554{
555 GLuint vbo_coords = 0;
556
557 if (attribute_v_coord != -1) {
558 fghGenBuffers(1, &vbo_coords);
559 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
560 fghBufferData(FGH_ARRAY_BUFFER, numNormalVertices * 3 * sizeof(verticesForNormalVisualization[0]),
561 verticesForNormalVisualization, FGH_STATIC_DRAW);
562 }
563
564
565 if (vbo_coords) {
566 fghEnableVertexAttribArray(attribute_v_coord);
567 fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
568 fghVertexAttribPointer(
569 attribute_v_coord, /* attribute */
570 3, /* number of elements per vertex, here (x,y,z) */
571 GL_FLOAT, /* the type of each element */
572 GL_FALSE, /* take our values as-is */
573 0, /* no extra data between each position */
574 0 /* offset of first element */
575 );
576 fghBindBuffer(FGH_ARRAY_BUFFER, 0);
577 }
578
579 glDrawArrays(GL_LINES, 0, numNormalVertices);
580
581 if (vbo_coords != 0)
582 fghDisableVertexAttribArray(attribute_v_coord);
583
584 if (vbo_coords != 0)
585 fghDeleteBuffers(1, &vbo_coords);
586
587 /* Done, free memory */
588 free(verticesForNormalVisualization);
589}
590
591/**
592 * Generate all combinations of vertices and normals needed to draw object.
593 * Optional shape decomposition to triangles:
594 * We'll use glDrawElements to draw all shapes that are not naturally
595 * composed of triangles, so generate an index vector here, using the
596 * below sampling scheme.
597 * Be careful to keep winding of all triangles counter-clockwise,
598 * assuming that input has correct winding...
599 */
600static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */
601static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */
602
603static void fghGenerateGeometryWithIndexArray(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut, GLushort *vertIdxOut)
604{
605 int i,j,numEdgeIdxPerFace;
606 GLubyte *vertSamps = NULL;
607 switch (numEdgePerFace)
608 {
609 case 3:
610 /* nothing to do here, we'll draw with glDrawArrays */
611 break;
612 case 4:
613 vertSamps = vert4Decomp;
614 numEdgeIdxPerFace = 6; /* 6 output vertices for each face */
615 break;
616 case 5:
617 vertSamps = vert5Decomp;
618 numEdgeIdxPerFace = 9; /* 9 output vertices for each face */
619 break;
620 }
621 /*
622 * Build array with vertices using vertex coordinates and vertex indices
623 * Do same for normals.
624 * Need to do this because of different normals at shared vertices.
625 */
626 for (i=0; i<numFaces; i++)
627 {
628 int normIdx = i*3;
629 int faceIdxVertIdx = i*numEdgePerFace; /* index to first element of "row" in vertex indices */
630 for (j=0; j<numEdgePerFace; j++)
631 {
632 int outIdx = i*numEdgePerFace*3+j*3;
633 int vertIdx = vertIndices[faceIdxVertIdx+j]*3;
634
635 vertOut[outIdx ] = vertices[vertIdx ];
636 vertOut[outIdx+1] = vertices[vertIdx+1];
637 vertOut[outIdx+2] = vertices[vertIdx+2];
638
639 normOut[outIdx ] = normals [normIdx ];
640 normOut[outIdx+1] = normals [normIdx+1];
641 normOut[outIdx+2] = normals [normIdx+2];
642 }
643
644 /* generate vertex indices for each face */
645 if (vertSamps)
646 for (j=0; j<numEdgeIdxPerFace; j++)
647 vertIdxOut[i*numEdgeIdxPerFace+j] = faceIdxVertIdx + vertSamps[j];
648 }
649}
650
651static void fghGenerateGeometry(int numFaces, int numEdgePerFace, GLfloat *vertices, GLubyte *vertIndices, GLfloat *normals, GLfloat *vertOut, GLfloat *normOut)
652{
653 /* This function does the same as fghGenerateGeometryWithIndexArray, just skipping the index array generation... */
654 fghGenerateGeometryWithIndexArray(numFaces, numEdgePerFace, vertices, vertIndices, normals, vertOut, normOut, NULL);
655}
656
657
658/* -- INTERNAL SETUP OF GEOMETRY --------------------------------------- */
659/* -- stuff that can be cached -- */
660/* Cache of input to glDrawArrays or glDrawElements
661 * In general, we build arrays with all vertices or normals.
662 * We cant compress this and use glDrawElements as all combinations of
663 * vertices and normals are unique.
664 */
665#define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
666 static GLboolean name##Cached = GL_FALSE;\
667 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
668 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
669 static void fgh##nameICaps##Generate()\
670 {\
671 fghGenerateGeometry(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
672 name##_v, name##_vi, name##_n,\
673 name##_verts, name##_norms);\
674 }
675#define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
676 static GLboolean name##Cached = GL_FALSE;\
677 static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
678 static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
679 static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
680 static void fgh##nameICaps##Generate()\
681 {\
682 fghGenerateGeometryWithIndexArray(nameCaps##_NUM_FACES, nameCaps##_NUM_EDGE_PER_FACE,\
683 name##_v, name##_vi, name##_n,\
684 name##_verts, name##_norms, name##_vertIdxs);\
685 }
686
687/* -- Cube -- */
688#define CUBE_NUM_VERT 8
689#define CUBE_NUM_FACES 6
690#define CUBE_NUM_EDGE_PER_FACE 4
691#define CUBE_VERT_PER_OBJ (CUBE_NUM_FACES*CUBE_NUM_EDGE_PER_FACE)
692#define CUBE_VERT_ELEM_PER_OBJ (CUBE_VERT_PER_OBJ*3)
693#define CUBE_VERT_PER_OBJ_TRI (CUBE_VERT_PER_OBJ+CUBE_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
694/* Vertex Coordinates */
695static GLfloat cube_v[CUBE_NUM_VERT*3] =
696{
697 .5f, .5f, .5f,
698 -.5f, .5f, .5f,
699 -.5f,-.5f, .5f,
700 .5f,-.5f, .5f,
701 .5f,-.5f,-.5f,
702 .5f, .5f,-.5f,
703 -.5f, .5f,-.5f,
704 -.5f,-.5f,-.5f
705};
706/* Normal Vectors */
707static GLfloat cube_n[CUBE_NUM_FACES*3] =
708{
709 0.0f, 0.0f, 1.0f,
710 1.0f, 0.0f, 0.0f,
711 0.0f, 1.0f, 0.0f,
712 -1.0f, 0.0f, 0.0f,
713 0.0f,-1.0f, 0.0f,
714 0.0f, 0.0f,-1.0f
715};
716
717/* Vertex indices, as quads, before triangulation */
718static GLubyte cube_vi[CUBE_VERT_PER_OBJ] =
719{
720 0,1,2,3,
721 0,3,4,5,
722 0,5,6,1,
723 1,6,7,2,
724 7,4,3,2,
725 4,7,6,5
726};
727DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(cube,Cube,CUBE)
728
729/* -- Dodecahedron -- */
730/* Magic Numbers: It is possible to create a dodecahedron by attaching two
731 * pentagons to each face of of a cube. The coordinates of the points are:
732 * (+-x,0, z); (+-1, 1, 1); (0, z, x )
733 * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
734 * x = 0.61803398875 and z = 1.61803398875.
735 */
736#define DODECAHEDRON_NUM_VERT 20
737#define DODECAHEDRON_NUM_FACES 12
738#define DODECAHEDRON_NUM_EDGE_PER_FACE 5
739#define DODECAHEDRON_VERT_PER_OBJ (DODECAHEDRON_NUM_FACES*DODECAHEDRON_NUM_EDGE_PER_FACE)
740#define DODECAHEDRON_VERT_ELEM_PER_OBJ (DODECAHEDRON_VERT_PER_OBJ*3)
741#define DODECAHEDRON_VERT_PER_OBJ_TRI (DODECAHEDRON_VERT_PER_OBJ+DODECAHEDRON_NUM_FACES*4) /* 4 extra edges per face when drawing pentagons as triangles */
742/* Vertex Coordinates */
743static GLfloat dodecahedron_v[DODECAHEDRON_NUM_VERT*3] =
744{
745 0.0f, 1.61803398875f, 0.61803398875f,
746 - 1.0f, 1.0f, 1.0f,
747 -0.61803398875f, 0.0f, 1.61803398875f,
748 0.61803398875f, 0.0f, 1.61803398875f,
749 1.0f, 1.0f, 1.0f,
750 0.0f, 1.61803398875f, -0.61803398875f,
751 1.0f, 1.0f, - 1.0f,
752 0.61803398875f, 0.0f, -1.61803398875f,
753 -0.61803398875f, 0.0f, -1.61803398875f,
754 - 1.0f, 1.0f, - 1.0f,
755 0.0f, -1.61803398875f, 0.61803398875f,
756 1.0f, - 1.0f, 1.0f,
757 - 1.0f, - 1.0f, 1.0f,
758 0.0f, -1.61803398875f, -0.61803398875f,
759 - 1.0f, - 1.0f, - 1.0f,
760 1.0f, - 1.0f, - 1.0f,
761 1.61803398875f, -0.61803398875f, 0.0f,
762 1.61803398875f, 0.61803398875f, 0.0f,
763 -1.61803398875f, 0.61803398875f, 0.0f,
764 -1.61803398875f, -0.61803398875f, 0.0f
765};
766/* Normal Vectors */
767static GLfloat dodecahedron_n[DODECAHEDRON_NUM_FACES*3] =
768{
769 0.0f, 0.525731112119f, 0.850650808354f,
770 0.0f, 0.525731112119f, -0.850650808354f,
771 0.0f, -0.525731112119f, 0.850650808354f,
772 0.0f, -0.525731112119f, -0.850650808354f,
773
774 0.850650808354f, 0.0f, 0.525731112119f,
775 -0.850650808354f, 0.0f, 0.525731112119f,
776 0.850650808354f, 0.0f, -0.525731112119f,
777 -0.850650808354f, 0.0f, -0.525731112119f,
778
779 0.525731112119f, 0.850650808354f, 0.0f,
780 0.525731112119f, -0.850650808354f, 0.0f,
781 -0.525731112119f, 0.850650808354f, 0.0f,
782 -0.525731112119f, -0.850650808354f, 0.0f,
783};
784
785/* Vertex indices */
786static GLubyte dodecahedron_vi[DODECAHEDRON_VERT_PER_OBJ] =
787{
788 0, 1, 2, 3, 4,
789 5, 6, 7, 8, 9,
790 10, 11, 3, 2, 12,
791 13, 14, 8, 7, 15,
792
793 3, 11, 16, 17, 4,
794 2, 1, 18, 19, 12,
795 7, 6, 17, 16, 15,
796 8, 14, 19, 18, 9,
797
798 17, 6, 5, 0, 4,
799 16, 11, 10, 13, 15,
800 18, 1, 0, 5, 9,
801 19, 14, 13, 10, 12
802};
803DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
804
805
806/* -- Icosahedron -- */
807#define ICOSAHEDRON_NUM_VERT 12
808#define ICOSAHEDRON_NUM_FACES 20
809#define ICOSAHEDRON_NUM_EDGE_PER_FACE 3
810#define ICOSAHEDRON_VERT_PER_OBJ (ICOSAHEDRON_NUM_FACES*ICOSAHEDRON_NUM_EDGE_PER_FACE)
811#define ICOSAHEDRON_VERT_ELEM_PER_OBJ (ICOSAHEDRON_VERT_PER_OBJ*3)
812#define ICOSAHEDRON_VERT_PER_OBJ_TRI ICOSAHEDRON_VERT_PER_OBJ
813/* Vertex Coordinates */
814static GLfloat icosahedron_v[ICOSAHEDRON_NUM_VERT*3] =
815{
816 1.0f, 0.0f, 0.0f,
817 0.447213595500f, 0.894427191000f, 0.0f,
818 0.447213595500f, 0.276393202252f, 0.850650808354f,
819 0.447213595500f, -0.723606797748f, 0.525731112119f,
820 0.447213595500f, -0.723606797748f, -0.525731112119f,
821 0.447213595500f, 0.276393202252f, -0.850650808354f,
822 -0.447213595500f, -0.894427191000f, 0.0f,
823 -0.447213595500f, -0.276393202252f, 0.850650808354f,
824 -0.447213595500f, 0.723606797748f, 0.525731112119f,
825 -0.447213595500f, 0.723606797748f, -0.525731112119f,
826 -0.447213595500f, -0.276393202252f, -0.850650808354f,
827 - 1.0f, 0.0f, 0.0f
828};
829/* Normal Vectors:
830 * 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] ) ;
831 * 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] ) ;
832 * 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] ) ;
833*/
834static GLfloat icosahedron_n[ICOSAHEDRON_NUM_FACES*3] =
835{
836 0.760845213037948f, 0.470228201835026f, 0.341640786498800f,
837 0.760845213036861f, -0.179611190632978f, 0.552786404500000f,
838 0.760845213033849f, -0.581234022404097f, 0.0f,
839 0.760845213036861f, -0.179611190632978f, -0.552786404500000f,
840 0.760845213037948f, 0.470228201835026f, -0.341640786498800f,
841 0.179611190628666f, 0.760845213037948f, 0.552786404498399f,
842 0.179611190634277f, -0.290617011204044f, 0.894427191000000f,
843 0.179611190633958f, -0.940456403667806f, 0.0f,
844 0.179611190634278f, -0.290617011204044f, -0.894427191000000f,
845 0.179611190628666f, 0.760845213037948f, -0.552786404498399f,
846 -0.179611190633958f, 0.940456403667806f, 0.0f,
847 -0.179611190634277f, 0.290617011204044f, 0.894427191000000f,
848 -0.179611190628666f, -0.760845213037948f, 0.552786404498399f,
849 -0.179611190628666f, -0.760845213037948f, -0.552786404498399f,
850 -0.179611190634277f, 0.290617011204044f, -0.894427191000000f,
851 -0.760845213036861f, 0.179611190632978f, -0.552786404500000f,
852 -0.760845213033849f, 0.581234022404097f, 0.0f,
853 -0.760845213036861f, 0.179611190632978f, 0.552786404500000f,
854 -0.760845213037948f, -0.470228201835026f, 0.341640786498800f,
855 -0.760845213037948f, -0.470228201835026f, -0.341640786498800f,
856};
857
858/* Vertex indices */
859static GLubyte icosahedron_vi[ICOSAHEDRON_VERT_PER_OBJ] =
860{
861 0, 1, 2 ,
862 0, 2, 3 ,
863 0, 3, 4 ,
864 0, 4, 5 ,
865 0, 5, 1 ,
866 1, 8, 2 ,
867 2, 7, 3 ,
868 3, 6, 4 ,
869 4, 10, 5 ,
870 5, 9, 1 ,
871 1, 9, 8 ,
872 2, 8, 7 ,
873 3, 7, 6 ,
874 4, 6, 10 ,
875 5, 10, 9 ,
876 11, 9, 10 ,
877 11, 8, 9 ,
878 11, 7, 8 ,
879 11, 6, 7 ,
880 11, 10, 6
881};
882DECLARE_SHAPE_CACHE(icosahedron,Icosahedron,ICOSAHEDRON)
883
884/* -- Octahedron -- */
885#define OCTAHEDRON_NUM_VERT 6
886#define OCTAHEDRON_NUM_FACES 8
887#define OCTAHEDRON_NUM_EDGE_PER_FACE 3
888#define OCTAHEDRON_VERT_PER_OBJ (OCTAHEDRON_NUM_FACES*OCTAHEDRON_NUM_EDGE_PER_FACE)
889#define OCTAHEDRON_VERT_ELEM_PER_OBJ (OCTAHEDRON_VERT_PER_OBJ*3)
890#define OCTAHEDRON_VERT_PER_OBJ_TRI OCTAHEDRON_VERT_PER_OBJ
891
892/* Vertex Coordinates */
893static GLfloat octahedron_v[OCTAHEDRON_NUM_VERT*3] =
894{
895 1.f, 0.f, 0.f,
896 0.f, 1.f, 0.f,
897 0.f, 0.f, 1.f,
898 -1.f, 0.f, 0.f,
899 0.f, -1.f, 0.f,
900 0.f, 0.f, -1.f,
901
902};
903/* Normal Vectors */
904static GLfloat octahedron_n[OCTAHEDRON_NUM_FACES*3] =
905{
906 0.577350269189f, 0.577350269189f, 0.577350269189f, /* sqrt(1/3) */
907 0.577350269189f, 0.577350269189f,-0.577350269189f,
908 0.577350269189f,-0.577350269189f, 0.577350269189f,
909 0.577350269189f,-0.577350269189f,-0.577350269189f,
910 -0.577350269189f, 0.577350269189f, 0.577350269189f,
911 -0.577350269189f, 0.577350269189f,-0.577350269189f,
912 -0.577350269189f,-0.577350269189f, 0.577350269189f,
913 -0.577350269189f,-0.577350269189f,-0.577350269189f
914
915};
916
917/* Vertex indices */
918static GLubyte octahedron_vi[OCTAHEDRON_VERT_PER_OBJ] =
919{
920 0, 1, 2,
921 0, 5, 1,
922 0, 2, 4,
923 0, 4, 5,
924 3, 2, 1,
925 3, 1, 5,
926 3, 4, 2,
927 3, 5, 4
928};
929DECLARE_SHAPE_CACHE(octahedron,Octahedron,OCTAHEDRON)
930
931/* -- RhombicDodecahedron -- */
932#define RHOMBICDODECAHEDRON_NUM_VERT 14
933#define RHOMBICDODECAHEDRON_NUM_FACES 12
934#define RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE 4
935#define RHOMBICDODECAHEDRON_VERT_PER_OBJ (RHOMBICDODECAHEDRON_NUM_FACES*RHOMBICDODECAHEDRON_NUM_EDGE_PER_FACE)
936#define RHOMBICDODECAHEDRON_VERT_ELEM_PER_OBJ (RHOMBICDODECAHEDRON_VERT_PER_OBJ*3)
937#define RHOMBICDODECAHEDRON_VERT_PER_OBJ_TRI (RHOMBICDODECAHEDRON_VERT_PER_OBJ+RHOMBICDODECAHEDRON_NUM_FACES*2) /* 2 extra edges per face when drawing quads as triangles */
938
939/* Vertex Coordinates */
940static GLfloat rhombicdodecahedron_v[RHOMBICDODECAHEDRON_NUM_VERT*3] =
941{
942 0.0f, 0.0f, 1.0f,
943 0.707106781187f, 0.0f, 0.5f,
944 0.0f, 0.707106781187f, 0.5f,
945 -0.707106781187f, 0.0f, 0.5f,
946 0.0f, -0.707106781187f, 0.5f,
947 0.707106781187f, 0.707106781187f, 0.0f,
948 -0.707106781187f, 0.707106781187f, 0.0f,
949 -0.707106781187f, -0.707106781187f, 0.0f,
950 0.707106781187f, -0.707106781187f, 0.0f,
951 0.707106781187f, 0.0f, -0.5f,
952 0.0f, 0.707106781187f, -0.5f,
953 -0.707106781187f, 0.0f, -0.5f,
954 0.0f, -0.707106781187f, -0.5f,
955 0.0f, 0.0f, -1.0f
956};
957/* Normal Vectors */
958static GLfloat rhombicdodecahedron_n[RHOMBICDODECAHEDRON_NUM_FACES*3] =
959{
960 0.353553390594f, 0.353553390594f, 0.5f,
961 -0.353553390594f, 0.353553390594f, 0.5f,
962 -0.353553390594f, -0.353553390594f, 0.5f,
963 0.353553390594f, -0.353553390594f, 0.5f,
964 0.0f, 1.0f, 0.0f,
965 - 1.0f, 0.0f, 0.0f,
966 0.0f, - 1.0f, 0.0f,
967 1.0f, 0.0f, 0.0f,
968 0.353553390594f, 0.353553390594f, -0.5f,
969 -0.353553390594f, 0.353553390594f, -0.5f,
970 -0.353553390594f, -0.353553390594f, -0.5f,
971 0.353553390594f, -0.353553390594f, -0.5f
972};
973
974/* Vertex indices */
975static GLubyte rhombicdodecahedron_vi[RHOMBICDODECAHEDRON_VERT_PER_OBJ] =
976{
977 0, 1, 5, 2,
978 0, 2, 6, 3,
979 0, 3, 7, 4,
980 0, 4, 8, 1,
981 5, 10, 6, 2,
982 6, 11, 7, 3,
983 7, 12, 8, 4,
984 8, 9, 5, 1,
985 5, 9, 13, 10,
986 6, 10, 13, 11,
987 7, 11, 13, 12,
988 8, 12, 13, 9
989};
990DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
991
992/* -- Tetrahedron -- */
993/* Magic Numbers: r0 = ( 1, 0, 0 )
994 * r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
995 * r2 = ( -1/3, - sqrt(2) / 3, sqrt(6) / 3 )
996 * r3 = ( -1/3, - sqrt(2) / 3, -sqrt(6) / 3 )
997 * |r0| = |r1| = |r2| = |r3| = 1
998 * Distance between any two points is 2 sqrt(6) / 3
999 *
1000 * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface.
1001 */
1002#define TETRAHEDRON_NUM_VERT 4
1003#define TETRAHEDRON_NUM_FACES 4
1004#define TETRAHEDRON_NUM_EDGE_PER_FACE 3
1005#define TETRAHEDRON_VERT_PER_OBJ (TETRAHEDRON_NUM_FACES*TETRAHEDRON_NUM_EDGE_PER_FACE)
1006#define TETRAHEDRON_VERT_ELEM_PER_OBJ (TETRAHEDRON_VERT_PER_OBJ*3)
1007#define TETRAHEDRON_VERT_PER_OBJ_TRI TETRAHEDRON_VERT_PER_OBJ
1008
1009/* Vertex Coordinates */
1010static GLfloat tetrahedron_v[TETRAHEDRON_NUM_VERT*3] =
1011{
1012 1.0f, 0.0f, 0.0f,
1013 -0.333333333333f, 0.942809041582f, 0.0f,
1014 -0.333333333333f, -0.471404520791f, 0.816496580928f,
1015 -0.333333333333f, -0.471404520791f, -0.816496580928f
1016};
1017/* Normal Vectors */
1018static GLfloat tetrahedron_n[TETRAHEDRON_NUM_FACES*3] =
1019{
1020 - 1.0f, 0.0f, 0.0f,
1021 0.333333333333f, -0.942809041582f, 0.0f,
1022 0.333333333333f, 0.471404520791f, -0.816496580928f,
1023 0.333333333333f, 0.471404520791f, 0.816496580928f
1024};
1025
1026/* Vertex indices */
1027static GLubyte tetrahedron_vi[TETRAHEDRON_VERT_PER_OBJ] =
1028{
1029 1, 3, 2,
1030 0, 2, 3,
1031 0, 3, 1,
1032 0, 1, 2
1033};
1034DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON)
1035
1036/* -- Sierpinski Sponge -- */
1037static unsigned int ipow (int x, unsigned int y)
1038{
1039 /* return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2); */
1040 if (y==0)
1041 return 1;
1042 else
1043 {
1044 if (y==1)
1045 return x;
1046 else
1047 {
1048 return (y%2? x: 1) * ipow(x*x, y/2);
1049 }
1050 }
1051}
1052
1053static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
1054{
1055 int i, j;
1056 if ( numLevels == 0 )
1057 {
1058 for (i=0; i<TETRAHEDRON_NUM_FACES; i++)
1059 {
1060 int normIdx = i*3;
1061 int faceIdxVertIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE;
1062 for (j=0; j<TETRAHEDRON_NUM_EDGE_PER_FACE; j++)
1063 {
1064 int outIdx = i*TETRAHEDRON_NUM_EDGE_PER_FACE*3+j*3;
1065 int vertIdx = tetrahedron_vi[faceIdxVertIdx+j]*3;
1066
1067 vertices[outIdx ] = (GLfloat)offset[0] + scale * tetrahedron_v[vertIdx ];
1068 vertices[outIdx+1] = (GLfloat)offset[1] + scale * tetrahedron_v[vertIdx+1];
1069 vertices[outIdx+2] = (GLfloat)offset[2] + scale * tetrahedron_v[vertIdx+2];
1070
1071 normals [outIdx ] = tetrahedron_n[normIdx ];
1072 normals [outIdx+1] = tetrahedron_n[normIdx+1];
1073 normals [outIdx+2] = tetrahedron_n[normIdx+2];
1074 }
1075 }
1076 }
1077 else if ( numLevels > 0 )
1078 {
1079 double local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */
1080 unsigned int stride = ipow(4,--numLevels)*TETRAHEDRON_VERT_ELEM_PER_OBJ;
1081 scale /= 2.0 ;
1082 for ( i = 0 ; i < TETRAHEDRON_NUM_FACES ; i++ )
1083 {
1084 int idx = i*3;
1085 local_offset[0] = offset[0] + scale * tetrahedron_v[idx ];
1086 local_offset[1] = offset[1] + scale * tetrahedron_v[idx+1];
1087 local_offset[2] = offset[2] + scale * tetrahedron_v[idx+2];
1088 fghSierpinskiSpongeGenerate ( numLevels, local_offset, scale, vertices+i*stride, normals+i*stride );
1089 }
1090 }
1091}
1092
1093/* -- Now the various non-polyhedra (shapes involving circles) -- */
1094/*
1095 * Compute lookup table of cos and sin values forming a circle
1096 * (or half circle if halfCircle==TRUE)
1097 *
1098 * Notes:
1099 * It is the responsibility of the caller to free these tables
1100 * The size of the table is (n+1) to form a connected loop
1101 * The last entry is exactly the same as the first
1102 * The sign of n can be flipped to get the reverse loop
1103 */
1104static void fghCircleTable(GLfloat **sint, GLfloat **cost, const int n, const GLboolean halfCircle)
1105{
1106 int i;
1107
1108 /* Table size, the sign of n flips the circle direction */
1109 const int size = abs(n);
1110
1111 /* Determine the angle between samples */
1112 const GLfloat angle = (halfCircle?1:2)*(GLfloat)M_PI/(GLfloat)( ( n == 0 ) ? 1 : n );
1113
1114 /* Allocate memory for n samples, plus duplicate of first entry at the end */
1115 *sint = malloc(sizeof(GLfloat) * (size+1));
1116 *cost = malloc(sizeof(GLfloat) * (size+1));
1117
1118 /* Bail out if memory allocation fails, fgError never returns */
1119 if (!(*sint) || !(*cost))
1120 {
1121 free(*sint);
1122 free(*cost);
1123 fgError("Failed to allocate memory in fghCircleTable");
1124 }
1125
1126 /* Compute cos and sin around the circle */
1127 (*sint)[0] = 0.0;
1128 (*cost)[0] = 1.0;
1129
1130 for (i=1; i<size; i++)
1131 {
1132 (*sint)[i] = (GLfloat)sin(angle*i);
1133 (*cost)[i] = (GLfloat)cos(angle*i);
1134 }
1135
1136
1137 if (halfCircle)
1138 {
1139 (*sint)[size] = 0.0f; /* sin PI */
1140 (*cost)[size] = -1.0f; /* cos PI */
1141 }
1142 else
1143 {
1144 /* Last sample is duplicate of the first (sin or cos of 2 PI) */
1145 (*sint)[size] = (*sint)[0];
1146 (*cost)[size] = (*cost)[0];
1147 }
1148}
1149
1150static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloat **vertices, GLfloat **normals, int* nVert)
1151{
1152 int i,j;
1153 int idx = 0; /* idx into vertex/normal buffer */
1154 GLfloat x,y,z;
1155
1156 /* Pre-computed circle */
1157 GLfloat *sint1,*cost1;
1158 GLfloat *sint2,*cost2;
1159
1160 /* number of unique vertices */
1161 if (slices==0 || stacks<2)
1162 {
1163 /* nothing to generate */
1164 *nVert = 0;
1165 return;
1166 }
1167 *nVert = slices*(stacks-1)+2;
1168 if ((*nVert) > 65535)
1169 /*
1170 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1171 */
1172 fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
1173
1174 /* precompute values on unit circle */
1175 fghCircleTable(&sint1,&cost1,-slices,GL_FALSE);
1176 fghCircleTable(&sint2,&cost2, stacks,GL_TRUE);
1177
1178 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1179 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1180 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1181 if (!(*vertices) || !(*normals))
1182 {
1183 free(*vertices);
1184 free(*normals);
1185 fgError("Failed to allocate memory in fghGenerateSphere");
1186 }
1187
1188 /* top */
1189 (*vertices)[0] = 0.f;
1190 (*vertices)[1] = 0.f;
1191 (*vertices)[2] = radius;
1192 (*normals )[0] = 0.f;
1193 (*normals )[1] = 0.f;
1194 (*normals )[2] = 1.f;
1195 idx = 3;
1196
1197 /* each stack */
1198 for( i=1; i<stacks; i++ )
1199 {
1200 for(j=0; j<slices; j++, idx+=3)
1201 {
1202 x = cost1[j]*sint2[i];
1203 y = sint1[j]*sint2[i];
1204 z = cost2[i];
1205
1206 (*vertices)[idx ] = x*radius;
1207 (*vertices)[idx+1] = y*radius;
1208 (*vertices)[idx+2] = z*radius;
1209 (*normals )[idx ] = x;
1210 (*normals )[idx+1] = y;
1211 (*normals )[idx+2] = z;
1212 }
1213 }
1214
1215 /* bottom */
1216 (*vertices)[idx ] = 0.f;
1217 (*vertices)[idx+1] = 0.f;
1218 (*vertices)[idx+2] = -radius;
1219 (*normals )[idx ] = 0.f;
1220 (*normals )[idx+1] = 0.f;
1221 (*normals )[idx+2] = -1.f;
1222
1223 /* Done creating vertices, release sin and cos tables */
1224 free(sint1);
1225 free(cost1);
1226 free(sint2);
1227 free(cost2);
1228}
1229
1230void fghGenerateCone(
1231 GLfloat base, GLfloat height, GLint slices, GLint stacks, /* input */
1232 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1233 )
1234{
1235 int i,j;
1236 int idx = 0; /* idx into vertex/normal buffer */
1237
1238 /* Pre-computed circle */
1239 GLfloat *sint,*cost;
1240
1241 /* Step in z and radius as stacks are drawn. */
1242 GLfloat z = 0;
1243 GLfloat r = (GLfloat)base;
1244
1245 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1246 const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
1247
1248 /* Scaling factors for vertex normals */
1249 const GLfloat cosn = (GLfloat) (height / sqrt( height * height + base * base ));
1250 const GLfloat sinn = (GLfloat) (base / sqrt( height * height + base * base ));
1251
1252
1253
1254 /* number of unique vertices */
1255 if (slices==0 || stacks<1)
1256 {
1257 /* nothing to generate */
1258 *nVert = 0;
1259 return;
1260 }
1261 *nVert = slices*(stacks+2)+1; /* need an extra stack for closing off bottom with correct normals */
1262
1263 if ((*nVert) > 65535)
1264 /*
1265 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1266 */
1267 fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
1268
1269 /* Pre-computed circle */
1270 fghCircleTable(&sint,&cost,-slices,GL_FALSE);
1271
1272 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1273 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1274 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1275 if (!(*vertices) || !(*normals))
1276 {
1277 free(*vertices);
1278 free(*normals);
1279 fgError("Failed to allocate memory in fghGenerateCone");
1280 }
1281
1282 /* bottom */
1283 (*vertices)[0] = 0.f;
1284 (*vertices)[1] = 0.f;
1285 (*vertices)[2] = z;
1286 (*normals )[0] = 0.f;
1287 (*normals )[1] = 0.f;
1288 (*normals )[2] = -1.f;
1289 idx = 3;
1290 /* other on bottom (get normals right) */
1291 for (j=0; j<slices; j++, idx+=3)
1292 {
1293 (*vertices)[idx ] = cost[j]*r;
1294 (*vertices)[idx+1] = sint[j]*r;
1295 (*vertices)[idx+2] = z;
1296 (*normals )[idx ] = 0.f;
1297 (*normals )[idx+1] = 0.f;
1298 (*normals )[idx+2] = -1.f;
1299 }
1300
1301 /* each stack */
1302 for (i=0; i<stacks+1; i++ )
1303 {
1304 for (j=0; j<slices; j++, idx+=3)
1305 {
1306 (*vertices)[idx ] = cost[j]*r;
1307 (*vertices)[idx+1] = sint[j]*r;
1308 (*vertices)[idx+2] = z;
1309 (*normals )[idx ] = cost[j]*cosn;
1310 (*normals )[idx+1] = sint[j]*cosn;
1311 (*normals )[idx+2] = sinn;
1312 }
1313
1314 z += zStep;
1315 r -= rStep;
1316 }
1317
1318 /* Release sin and cos tables */
1319 free(sint);
1320 free(cost);
1321}
1322
1323void fghGenerateCylinder(
1324 GLfloat radius, GLfloat height, GLint slices, GLint stacks, /* input */
1325 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1326 )
1327{
1328 int i,j;
1329 int idx = 0; /* idx into vertex/normal buffer */
1330
1331 /* Step in z as stacks are drawn. */
1332 GLfloat radf = (GLfloat)radius;
1333 GLfloat z;
1334 const GLfloat zStep = (GLfloat)height / ( ( stacks > 0 ) ? stacks : 1 );
1335
1336 /* Pre-computed circle */
1337 GLfloat *sint,*cost;
1338
1339 /* number of unique vertices */
1340 if (slices==0 || stacks<1)
1341 {
1342 /* nothing to generate */
1343 *nVert = 0;
1344 return;
1345 }
1346 *nVert = slices*(stacks+3)+2; /* need two extra stacks for closing off top and bottom with correct normals */
1347
1348 if ((*nVert) > 65535)
1349 /*
1350 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1351 */
1352 fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
1353
1354 /* Pre-computed circle */
1355 fghCircleTable(&sint,&cost,-slices,GL_FALSE);
1356
1357 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1358 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1359 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1360 if (!(*vertices) || !(*normals))
1361 {
1362 free(*vertices);
1363 free(*normals);
1364 fgError("Failed to allocate memory in fghGenerateCylinder");
1365 }
1366
1367 z=0;
1368 /* top on Z-axis */
1369 (*vertices)[0] = 0.f;
1370 (*vertices)[1] = 0.f;
1371 (*vertices)[2] = 0.f;
1372 (*normals )[0] = 0.f;
1373 (*normals )[1] = 0.f;
1374 (*normals )[2] = -1.f;
1375 idx = 3;
1376 /* other on top (get normals right) */
1377 for (j=0; j<slices; j++, idx+=3)
1378 {
1379 (*vertices)[idx ] = cost[j]*radf;
1380 (*vertices)[idx+1] = sint[j]*radf;
1381 (*vertices)[idx+2] = z;
1382 (*normals )[idx ] = 0.f;
1383 (*normals )[idx+1] = 0.f;
1384 (*normals )[idx+2] = -1.f;
1385 }
1386
1387 /* each stack */
1388 for (i=0; i<stacks+1; i++ )
1389 {
1390 for (j=0; j<slices; j++, idx+=3)
1391 {
1392 (*vertices)[idx ] = cost[j]*radf;
1393 (*vertices)[idx+1] = sint[j]*radf;
1394 (*vertices)[idx+2] = z;
1395 (*normals )[idx ] = cost[j];
1396 (*normals )[idx+1] = sint[j];
1397 (*normals )[idx+2] = 0.f;
1398 }
1399
1400 z += zStep;
1401 }
1402
1403 /* other on bottom (get normals right) */
1404 z -= zStep;
1405 for (j=0; j<slices; j++, idx+=3)
1406 {
1407 (*vertices)[idx ] = cost[j]*radf;
1408 (*vertices)[idx+1] = sint[j]*radf;
1409 (*vertices)[idx+2] = z;
1410 (*normals )[idx ] = 0.f;
1411 (*normals )[idx+1] = 0.f;
1412 (*normals )[idx+2] = 1.f;
1413 }
1414
1415 /* bottom */
1416 (*vertices)[idx ] = 0.f;
1417 (*vertices)[idx+1] = 0.f;
1418 (*vertices)[idx+2] = height;
1419 (*normals )[idx ] = 0.f;
1420 (*normals )[idx+1] = 0.f;
1421 (*normals )[idx+2] = 1.f;
1422
1423 /* Release sin and cos tables */
1424 free(sint);
1425 free(cost);
1426}
1427
1428void fghGenerateTorus(
1429 double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /* input */
1430 GLfloat **vertices, GLfloat **normals, int* nVert /* output */
1431 )
1432{
1433 GLfloat iradius = (float)dInnerRadius;
1434 GLfloat oradius = (float)dOuterRadius;
1435 int i, j;
1436
1437 /* Pre-computed circle */
1438 GLfloat *spsi, *cpsi;
1439 GLfloat *sphi, *cphi;
1440
1441 /* number of unique vertices */
1442 if (nSides<2 || nRings<2)
1443 {
1444 /* nothing to generate */
1445 *nVert = 0;
1446 return;
1447 }
1448 *nVert = nSides * nRings;
1449
1450 if ((*nVert) > 65535)
1451 /*
1452 * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
1453 */
1454 fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
1455
1456 /* precompute values on unit circle */
1457 fghCircleTable(&spsi,&cpsi, nRings,GL_FALSE);
1458 fghCircleTable(&sphi,&cphi,-nSides,GL_FALSE);
1459
1460 /* Allocate vertex and normal buffers, bail out if memory allocation fails */
1461 *vertices = malloc((*nVert)*3*sizeof(GLfloat));
1462 *normals = malloc((*nVert)*3*sizeof(GLfloat));
1463 if (!(*vertices) || !(*normals))
1464 {
1465 free(*vertices);
1466 free(*normals);
1467 fgError("Failed to allocate memory in fghGenerateTorus");
1468 }
1469
1470 for( j=0; j<nRings; j++ )
1471 {
1472 for( i=0; i<nSides; i++ )
1473 {
1474 int offset = 3 * ( j * nSides + i ) ;
1475
1476 (*vertices)[offset ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
1477 (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
1478 (*vertices)[offset+2] = sphi[i] * iradius ;
1479 (*normals )[offset ] = cpsi[j] * cphi[i] ;
1480 (*normals )[offset+1] = spsi[j] * cphi[i] ;
1481 (*normals )[offset+2] = sphi[i] ;
1482 }
1483 }
1484
1485 /* Release sin and cos tables */
1486 free(spsi);
1487 free(cpsi);
1488 free(sphi);
1489 free(cphi);
1490}
1491
1492/* -- INTERNAL DRAWING functions --------------------------------------- */
1493#define _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,vertIdxs)\
1494 static void fgh##nameICaps( GLboolean useWireMode )\
1495 {\
1496 if (!name##Cached)\
1497 {\
1498 fgh##nameICaps##Generate();\
1499 name##Cached = GL_TRUE;\
1500 }\
1501 \
1502 if (useWireMode)\
1503 {\
1504 fghDrawGeometryWire (name##_verts,name##_norms,nameCaps##_VERT_PER_OBJ, \
1505 NULL,nameCaps##_NUM_FACES,nameCaps##_NUM_EDGE_PER_FACE,GL_LINE_LOOP,\
1506 NULL,0,0);\
1507 }\
1508 else\
1509 {\
1510 fghDrawGeometrySolid(name##_verts,name##_norms,NULL,nameCaps##_VERT_PER_OBJ,\
1511 vertIdxs, 1, nameCaps##_VERT_PER_OBJ_TRI); \
1512 }\
1513 }
1514#define DECLARE_INTERNAL_DRAW(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,NULL)
1515#define DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(name,nameICaps,nameCaps) _DECLARE_INTERNAL_DRAW_DO_DECLARE(name,nameICaps,nameCaps,name##_vertIdxs)
1516
1517static void fghCube( GLfloat dSize, GLboolean useWireMode )
1518{
1519 GLfloat *vertices;
1520
1521 if (!cubeCached)
1522 {
1523 fghCubeGenerate();
1524 cubeCached = GL_TRUE;
1525 }
1526
1527 if (dSize!=1.f)
1528 {
1529 /* Need to build new vertex list containing vertices for cube of different size */
1530 int i;
1531
1532 vertices = malloc(CUBE_VERT_ELEM_PER_OBJ * sizeof(GLfloat));
1533
1534 /* Bail out if memory allocation fails, fgError never returns */
1535 if (!vertices)
1536 {
1537 free(vertices);
1538 fgError("Failed to allocate memory in fghCube");
1539 }
1540
1541 for (i=0; i<CUBE_VERT_ELEM_PER_OBJ; i++)
1542 vertices[i] = dSize*cube_verts[i];
1543 }
1544 else
1545 vertices = cube_verts;
1546
1547 if (useWireMode)
1548 fghDrawGeometryWire(vertices, cube_norms, CUBE_VERT_PER_OBJ,
1549 NULL,CUBE_NUM_FACES, CUBE_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1550 NULL,0,0);
1551 else
1552 fghDrawGeometrySolid(vertices, cube_norms, NULL, CUBE_VERT_PER_OBJ,
1553 cube_vertIdxs, 1, CUBE_VERT_PER_OBJ_TRI);
1554
1555 if (dSize!=1.f)
1556 /* cleanup allocated memory */
1557 free(vertices);
1558}
1559
1560DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON)
1561DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON)
1562DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON)
1563DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON)
1564DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON)
1565
1566static void fghSierpinskiSponge ( int numLevels, double offset[3], GLfloat scale, GLboolean useWireMode )
1567{
1568 GLfloat *vertices;
1569 GLfloat * normals;
1570 GLsizei numTetr = numLevels<0? 0 : ipow(4,numLevels); /* No sponge for numLevels below 0 */
1571 GLsizei numVert = numTetr*TETRAHEDRON_VERT_PER_OBJ;
1572 GLsizei numFace = numTetr*TETRAHEDRON_NUM_FACES;
1573
1574 if (numTetr)
1575 {
1576 /* Allocate memory */
1577 vertices = malloc(numVert*3 * sizeof(GLfloat));
1578 normals = malloc(numVert*3 * sizeof(GLfloat));
1579 /* Bail out if memory allocation fails, fgError never returns */
1580 if (!vertices || !normals)
1581 {
1582 free(vertices);
1583 free(normals);
1584 fgError("Failed to allocate memory in fghSierpinskiSponge");
1585 }
1586
1587 /* Generate elements */
1588 fghSierpinskiSpongeGenerate ( numLevels, offset, scale, vertices, normals );
1589
1590 /* Draw and cleanup */
1591 if (useWireMode)
1592 fghDrawGeometryWire (vertices,normals,numVert,
1593 NULL,numFace,TETRAHEDRON_NUM_EDGE_PER_FACE,GL_LINE_LOOP,
1594 NULL,0,0);
1595 else
1596 fghDrawGeometrySolid(vertices,normals,NULL,numVert,NULL,1,0);
1597
1598 free(vertices);
1599 free(normals );
1600 }
1601}
1602
1603
1604static void fghSphere( GLfloat radius, GLint slices, GLint stacks, GLboolean useWireMode )
1605{
1606 int i,j,idx, nVert;
1607 GLfloat *vertices, *normals;
1608
1609 /* Generate vertices and normals */
1610 fghGenerateSphere(radius,slices,stacks,&vertices,&normals,&nVert);
1611
1612 if (nVert==0)
1613 /* nothing to draw */
1614 return;
1615
1616 if (useWireMode)
1617 {
1618 GLushort *sliceIdx, *stackIdx;
1619 /* First, generate vertex index arrays for drawing with glDrawElements
1620 * We have a bunch of line_loops to draw for each stack, and a
1621 * bunch for each slice.
1622 */
1623
1624 sliceIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1625 stackIdx = malloc(slices*(stacks-1)*sizeof(GLushort));
1626 if (!(stackIdx) || !(sliceIdx))
1627 {
1628 free(stackIdx);
1629 free(sliceIdx);
1630 fgError("Failed to allocate memory in fghSphere");
1631 }
1632
1633 /* generate for each stack */
1634 for (i=0,idx=0; i<stacks-1; i++)
1635 {
1636 GLushort offset = 1+i*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1637 for (j=0; j<slices; j++, idx++)
1638 {
1639 stackIdx[idx] = offset+j;
1640 }
1641 }
1642
1643 /* generate for each slice */
1644 for (i=0,idx=0; i<slices; i++)
1645 {
1646 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1647 sliceIdx[idx++] = 0; /* vertex on top */
1648 for (j=0; j<stacks-1; j++, idx++)
1649 {
1650 sliceIdx[idx] = offset+j*slices;
1651 }
1652 sliceIdx[idx++] = nVert-1; /* zero based index, last element in array... */
1653 }
1654
1655 /* draw */
1656 fghDrawGeometryWire(vertices,normals,nVert,
1657 sliceIdx,slices,stacks+1,GL_LINE_STRIP,
1658 stackIdx,stacks-1,slices);
1659
1660 /* cleanup allocated memory */
1661 free(sliceIdx);
1662 free(stackIdx);
1663 }
1664 else
1665 {
1666 /* First, generate vertex index arrays for drawing with glDrawElements
1667 * All stacks, including top and bottom are covered with a triangle
1668 * strip.
1669 */
1670 GLushort *stripIdx;
1671 /* Create index vector */
1672 GLushort offset;
1673
1674 /* Allocate buffers for indices, bail out if memory allocation fails */
1675 stripIdx = malloc((slices+1)*2*(stacks)*sizeof(GLushort));
1676 if (!(stripIdx))
1677 {
1678 free(stripIdx);
1679 fgError("Failed to allocate memory in fghSphere");
1680 }
1681
1682 /* top stack */
1683 for (j=0, idx=0; j<slices; j++, idx+=2)
1684 {
1685 stripIdx[idx ] = j+1; /* 0 is top vertex, 1 is first for first stack */
1686 stripIdx[idx+1] = 0;
1687 }
1688 stripIdx[idx ] = 1; /* repeat first slice's idx for closing off shape */
1689 stripIdx[idx+1] = 0;
1690 idx+=2;
1691
1692 /* middle stacks: */
1693 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1694 for (i=0; i<stacks-2; i++, idx+=2)
1695 {
1696 offset = 1+i*slices; /* triangle_strip indices start at 1 (0 is top vertex), and we advance one stack down as we go along */
1697 for (j=0; j<slices; j++, idx+=2)
1698 {
1699 stripIdx[idx ] = offset+j+slices;
1700 stripIdx[idx+1] = offset+j;
1701 }
1702 stripIdx[idx ] = offset+slices; /* repeat first slice's idx for closing off shape */
1703 stripIdx[idx+1] = offset;
1704 }
1705
1706 /* bottom stack */
1707 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 */
1708 for (j=0; j<slices; j++, idx+=2)
1709 {
1710 stripIdx[idx ] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1711 stripIdx[idx+1] = offset+j;
1712 }
1713 stripIdx[idx ] = nVert-1; /* repeat first slice's idx for closing off shape */
1714 stripIdx[idx+1] = offset;
1715
1716
1717 /* draw */
1718 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,stacks,(slices+1)*2);
1719
1720 /* cleanup allocated memory */
1721 free(stripIdx);
1722 }
1723
1724 /* cleanup allocated memory */
1725 free(vertices);
1726 free(normals);
1727}
1728
1729static void fghCone( GLfloat base, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1730{
1731 int i,j,idx, nVert;
1732 GLfloat *vertices, *normals;
1733
1734 /* Generate vertices and normals */
1735 /* Note, (stacks+1)*slices vertices for side of object, slices+1 for top and bottom closures */
1736 fghGenerateCone(base,height,slices,stacks,&vertices,&normals,&nVert);
1737
1738 if (nVert==0)
1739 /* nothing to draw */
1740 return;
1741
1742 if (useWireMode)
1743 {
1744 GLushort *sliceIdx, *stackIdx;
1745 /* First, generate vertex index arrays for drawing with glDrawElements
1746 * We have a bunch of line_loops to draw for each stack, and a
1747 * bunch for each slice.
1748 */
1749
1750 stackIdx = malloc(slices*stacks*sizeof(GLushort));
1751 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1752 if (!(stackIdx) || !(sliceIdx))
1753 {
1754 free(stackIdx);
1755 free(sliceIdx);
1756 fgError("Failed to allocate memory in fghCone");
1757 }
1758
1759 /* generate for each stack */
1760 for (i=0,idx=0; i<stacks; i++)
1761 {
1762 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1763 for (j=0; j<slices; j++, idx++)
1764 {
1765 stackIdx[idx] = offset+j;
1766 }
1767 }
1768
1769 /* generate for each slice */
1770 for (i=0,idx=0; i<slices; i++)
1771 {
1772 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1773 sliceIdx[idx++] = offset+slices;
1774 sliceIdx[idx++] = offset+(stacks+1)*slices;
1775 }
1776
1777 /* draw */
1778 fghDrawGeometryWire(vertices,normals,nVert,
1779 sliceIdx,1,slices*2,GL_LINES,
1780 stackIdx,stacks,slices);
1781
1782 /* cleanup allocated memory */
1783 free(sliceIdx);
1784 free(stackIdx);
1785 }
1786 else
1787 {
1788 /* First, generate vertex index arrays for drawing with glDrawElements
1789 * All stacks, including top and bottom are covered with a triangle
1790 * strip.
1791 */
1792 GLushort *stripIdx;
1793 /* Create index vector */
1794 GLushort offset;
1795
1796 /* Allocate buffers for indices, bail out if memory allocation fails */
1797 stripIdx = malloc((slices+1)*2*(stacks+1)*sizeof(GLushort)); /*stacks +1 because of closing off bottom */
1798 if (!(stripIdx))
1799 {
1800 free(stripIdx);
1801 fgError("Failed to allocate memory in fghCone");
1802 }
1803
1804 /* top stack */
1805 for (j=0, idx=0; j<slices; j++, idx+=2)
1806 {
1807 stripIdx[idx ] = 0;
1808 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1809 }
1810 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1811 stripIdx[idx+1] = 1;
1812 idx+=2;
1813
1814 /* middle stacks: */
1815 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1816 for (i=0; i<stacks; i++, idx+=2)
1817 {
1818 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 */
1819 for (j=0; j<slices; j++, idx+=2)
1820 {
1821 stripIdx[idx ] = offset+j;
1822 stripIdx[idx+1] = offset+j+slices;
1823 }
1824 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1825 stripIdx[idx+1] = offset+slices;
1826 }
1827
1828 /* draw */
1829 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,stacks+1,(slices+1)*2);
1830
1831 /* cleanup allocated memory */
1832 free(stripIdx);
1833 }
1834
1835 /* cleanup allocated memory */
1836 free(vertices);
1837 free(normals);
1838}
1839
1840static void fghCylinder( GLfloat radius, GLfloat height, GLint slices, GLint stacks, GLboolean useWireMode )
1841{
1842 int i,j,idx, nVert;
1843 GLfloat *vertices, *normals;
1844
1845 /* Generate vertices and normals */
1846 /* Note, (stacks+1)*slices vertices for side of object, 2*slices+2 for top and bottom closures */
1847 fghGenerateCylinder(radius,height,slices,stacks,&vertices,&normals,&nVert);
1848
1849 if (nVert==0)
1850 /* nothing to draw */
1851 return;
1852
1853 if (useWireMode)
1854 {
1855 GLushort *sliceIdx, *stackIdx;
1856 /* First, generate vertex index arrays for drawing with glDrawElements
1857 * We have a bunch of line_loops to draw for each stack, and a
1858 * bunch for each slice.
1859 */
1860
1861 stackIdx = malloc(slices*(stacks+1)*sizeof(GLushort));
1862 sliceIdx = malloc(slices*2 *sizeof(GLushort));
1863 if (!(stackIdx) || !(sliceIdx))
1864 {
1865 free(stackIdx);
1866 free(sliceIdx);
1867 fgError("Failed to allocate memory in fghCylinder");
1868 }
1869
1870 /* generate for each stack */
1871 for (i=0,idx=0; i<stacks+1; i++)
1872 {
1873 GLushort offset = 1+(i+1)*slices; /* start at 1 (0 is top vertex), and we advance one stack down as we go along */
1874 for (j=0; j<slices; j++, idx++)
1875 {
1876 stackIdx[idx] = offset+j;
1877 }
1878 }
1879
1880 /* generate for each slice */
1881 for (i=0,idx=0; i<slices; i++)
1882 {
1883 GLushort offset = 1+i; /* start at 1 (0 is top vertex), and we advance one slice as we go along */
1884 sliceIdx[idx++] = offset+slices;
1885 sliceIdx[idx++] = offset+(stacks+1)*slices;
1886 }
1887
1888 /* draw */
1889 fghDrawGeometryWire(vertices,normals,nVert,
1890 sliceIdx,1,slices*2,GL_LINES,
1891 stackIdx,stacks+1,slices);
1892
1893 /* cleanup allocated memory */
1894 free(sliceIdx);
1895 free(stackIdx);
1896 }
1897 else
1898 {
1899 /* First, generate vertex index arrays for drawing with glDrawElements
1900 * All stacks, including top and bottom are covered with a triangle
1901 * strip.
1902 */
1903 GLushort *stripIdx;
1904 /* Create index vector */
1905 GLushort offset;
1906
1907 /* Allocate buffers for indices, bail out if memory allocation fails */
1908 stripIdx = malloc((slices+1)*2*(stacks+2)*sizeof(GLushort)); /*stacks +2 because of closing off bottom and top */
1909 if (!(stripIdx))
1910 {
1911 free(stripIdx);
1912 fgError("Failed to allocate memory in fghCylinder");
1913 }
1914
1915 /* top stack */
1916 for (j=0, idx=0; j<slices; j++, idx+=2)
1917 {
1918 stripIdx[idx ] = 0;
1919 stripIdx[idx+1] = j+1; /* 0 is top vertex, 1 is first for first stack */
1920 }
1921 stripIdx[idx ] = 0; /* repeat first slice's idx for closing off shape */
1922 stripIdx[idx+1] = 1;
1923 idx+=2;
1924
1925 /* middle stacks: */
1926 /* Strip indices are relative to first index belonging to strip, NOT relative to first vertex/normal pair in array */
1927 for (i=0; i<stacks; i++, idx+=2)
1928 {
1929 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 */
1930 for (j=0; j<slices; j++, idx+=2)
1931 {
1932 stripIdx[idx ] = offset+j;
1933 stripIdx[idx+1] = offset+j+slices;
1934 }
1935 stripIdx[idx ] = offset; /* repeat first slice's idx for closing off shape */
1936 stripIdx[idx+1] = offset+slices;
1937 }
1938
1939 /* top stack */
1940 offset = 1+(stacks+2)*slices;
1941 for (j=0; j<slices; j++, idx+=2)
1942 {
1943 stripIdx[idx ] = offset+j;
1944 stripIdx[idx+1] = nVert-1; /* zero based index, last element in array (bottom vertex)... */
1945 }
1946 stripIdx[idx ] = offset;
1947 stripIdx[idx+1] = nVert-1; /* repeat first slice's idx for closing off shape */
1948
1949 /* draw */
1950 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,stacks+2,(slices+1)*2);
1951
1952 /* cleanup allocated memory */
1953 free(stripIdx);
1954 }
1955
1956 /* cleanup allocated memory */
1957 free(vertices);
1958 free(normals);
1959}
1960
1961static void fghTorus( GLfloat dInnerRadius, GLfloat dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
1962{
1963 int i,j,idx, nVert;
1964 GLfloat *vertices, *normals;
1965
1966 /* Generate vertices and normals */
1967 fghGenerateTorus(dInnerRadius,dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
1968
1969 if (nVert==0)
1970 /* nothing to draw */
1971 return;
1972
1973 if (useWireMode)
1974 {
1975 GLushort *sideIdx, *ringIdx;
1976 /* First, generate vertex index arrays for drawing with glDrawElements
1977 * We have a bunch of line_loops to draw each side, and a
1978 * bunch for each ring.
1979 */
1980
1981 ringIdx = malloc(nRings*nSides*sizeof(GLushort));
1982 sideIdx = malloc(nSides*nRings*sizeof(GLushort));
1983 if (!(ringIdx) || !(sideIdx))
1984 {
1985 free(ringIdx);
1986 free(sideIdx);
1987 fgError("Failed to allocate memory in fghTorus");
1988 }
1989
1990 /* generate for each ring */
1991 for( j=0,idx=0; j<nRings; j++ )
1992 for( i=0; i<nSides; i++, idx++ )
1993 ringIdx[idx] = j * nSides + i;
1994
1995 /* generate for each side */
1996 for( i=0,idx=0; i<nSides; i++ )
1997 for( j=0; j<nRings; j++, idx++ )
1998 sideIdx[idx] = j * nSides + i;
1999
2000 /* draw */
2001 fghDrawGeometryWire(vertices,normals,nVert,
2002 ringIdx,nRings,nSides,GL_LINE_LOOP,
2003 sideIdx,nSides,nRings);
2004
2005 /* cleanup allocated memory */
2006 free(sideIdx);
2007 free(ringIdx);
2008 }
2009 else
2010 {
2011 /* First, generate vertex index arrays for drawing with glDrawElements
2012 * All stacks, including top and bottom are covered with a triangle
2013 * strip.
2014 */
2015 GLushort *stripIdx;
2016
2017 /* Allocate buffers for indices, bail out if memory allocation fails */
2018 stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
2019 if (!(stripIdx))
2020 {
2021 free(stripIdx);
2022 fgError("Failed to allocate memory in fghTorus");
2023 }
2024
2025 for( i=0, idx=0; i<nSides; i++ )
2026 {
2027 int ioff = 1;
2028 if (i==nSides-1)
2029 ioff = -i;
2030
2031 for( j=0; j<nRings; j++, idx+=2 )
2032 {
2033 int offset = j * nSides + i;
2034 stripIdx[idx ] = offset;
2035 stripIdx[idx+1] = offset + ioff;
2036 }
2037 /* repeat first to close off shape */
2038 stripIdx[idx ] = i;
2039 stripIdx[idx+1] = i + ioff;
2040 idx +=2;
2041 }
2042
2043 /* draw */
2044 fghDrawGeometrySolid(vertices,normals,NULL,nVert,stripIdx,nSides,(nRings+1)*2);
2045
2046 /* cleanup allocated memory */
2047 free(stripIdx);
2048 }
2049
2050 /* cleanup allocated memory */
2051 free(vertices);
2052 free(normals);
2053}
2054
2055
2056/* -- INTERFACE FUNCTIONS ---------------------------------------------- */
2057
2058
2059/*
2060 * Draws a solid sphere
2061 */
2062void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
2063{
2064 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
2065 fghSphere((GLfloat)radius, slices, stacks, GL_FALSE );
2066}
2067
2068/*
2069 * Draws a wire sphere
2070 */
2071void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
2072{
2073 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
2074 fghSphere((GLfloat)radius, slices, stacks, GL_TRUE );
2075
2076}
2077
2078/*
2079 * Draws a solid cone
2080 */
2081void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
2082{
2083 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
2084 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, GL_FALSE );
2085}
2086
2087/*
2088 * Draws a wire cone
2089 */
2090void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
2091{
2092 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
2093 fghCone((GLfloat)base, (GLfloat)height, slices, stacks, GL_TRUE );
2094}
2095
2096
2097/*
2098 * Draws a solid cylinder
2099 */
2100void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
2101{
2102 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
2103 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, GL_FALSE );
2104}
2105
2106/*
2107 * Draws a wire cylinder
2108 */
2109void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
2110{
2111 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
2112 fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, GL_TRUE );
2113}
2114
2115/*
2116 * Draws a wire torus
2117 */
2118void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2119{
2120 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
2121 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, GL_TRUE);
2122}
2123
2124/*
2125 * Draws a solid torus
2126 */
2127void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
2128{
2129 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
2130 fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, GL_FALSE);
2131}
2132
2133
2134
2135/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
2136/* Macro to generate interface functions */
2137#define DECLARE_SHAPE_INTERFACE(nameICaps)\
2138 void FGAPIENTRY glutWire##nameICaps( void )\
2139 {\
2140 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
2141 fgh##nameICaps( GL_TRUE );\
2142 }\
2143 void FGAPIENTRY glutSolid##nameICaps( void )\
2144 {\
2145 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
2146 fgh##nameICaps( GL_FALSE );\
2147 }
2148
2149void FGAPIENTRY glutWireCube( double dSize )
2150{
2151 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
2152 fghCube( (GLfloat)dSize, GL_TRUE );
2153}
2154void FGAPIENTRY glutSolidCube( double dSize )
2155{
2156 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
2157 fghCube( (GLfloat)dSize, GL_FALSE );
2158}
2159
2160DECLARE_SHAPE_INTERFACE(Dodecahedron)
2161DECLARE_SHAPE_INTERFACE(Icosahedron)
2162DECLARE_SHAPE_INTERFACE(Octahedron)
2163DECLARE_SHAPE_INTERFACE(RhombicDodecahedron)
2164
2165void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
2166{
2167 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
2168 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, GL_TRUE );
2169}
2170void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
2171{
2172 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
2173 fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, GL_FALSE );
2174}
2175
2176DECLARE_SHAPE_INTERFACE(Tetrahedron)
2177
2178
2179/*** END OF FILE ***/
2180