Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/freeglut/src/fg_geometry.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 */ | |
| 47 static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals, | |
| 48 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode, | |
| 49 GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2 | |
| 50 ); | |
| 51 static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLfloat *textcs, GLsizei numVertices, | |
| 52 GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart); | |
| 53 static 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 ); | |
| 58 static 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 */ | |
| 62 static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices); | |
| 63 static void fghDrawNormalVisualization11(); | |
| 64 static 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 */ | |
| 132 void 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 */ | |
| 178 void 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 */ | |
| 214 static 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 | |
| 245 static 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 */ | |
| 278 static 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 */ | |
| 390 static 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 */ | |
| 513 static GLfloat *verticesForNormalVisualization; | |
| 514 static GLsizei numNormalVertices = 0; | |
| 515 static 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 */ | |
| 533 static 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 */ | |
| 553 static 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 */ | |
| 600 static GLubyte vert4Decomp[6] = {0,1,2, 0,2,3}; /* quad : 4 input vertices, 6 output (2 triangles) */ | |
| 601 static GLubyte vert5Decomp[9] = {0,1,2, 0,2,4, 4,2,3}; /* pentagon: 5 input vertices, 9 output (3 triangles) */ | |
| 602 | |
| 603 static 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 | |
| 651 static 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 */ | |
| 695 static 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 */ | |
| 707 static 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 */ | |
| 718 static 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 }; | |
| 727 DECLARE_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 */ | |
| 743 static 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 */ | |
| 767 static 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 */ | |
| 786 static 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 }; | |
| 803 DECLARE_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 */ | |
| 814 static 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 */ | |
| 834 static 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 */ | |
| 859 static 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 }; | |
| 882 DECLARE_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 */ | |
| 893 static 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 */ | |
| 904 static 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 */ | |
| 918 static 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 }; | |
| 929 DECLARE_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 */ | |
| 940 static 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 */ | |
| 958 static 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 */ | |
| 975 static 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 }; | |
| 990 DECLARE_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 */ | |
| 1010 static 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 */ | |
| 1018 static 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 */ | |
| 1027 static 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 }; | |
| 1034 DECLARE_SHAPE_CACHE(tetrahedron,Tetrahedron,TETRAHEDRON) | |
| 1035 | |
| 1036 /* -- Sierpinski Sponge -- */ | |
| 1037 static 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 | |
| 1053 static 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 */ | |
| 1104 static 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 | |
| 1150 static 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 | |
| 1230 void 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 | |
| 1323 void 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 | |
| 1428 void 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 | |
| 1517 static 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 | |
| 1560 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(dodecahedron,Dodecahedron,DODECAHEDRON) | |
| 1561 DECLARE_INTERNAL_DRAW(icosahedron,Icosahedron,ICOSAHEDRON) | |
| 1562 DECLARE_INTERNAL_DRAW(octahedron,Octahedron,OCTAHEDRON) | |
| 1563 DECLARE_INTERNAL_DRAW_DECOMPOSED_TO_TRIANGLE(rhombicdodecahedron,RhombicDodecahedron,RHOMBICDODECAHEDRON) | |
| 1564 DECLARE_INTERNAL_DRAW(tetrahedron,Tetrahedron,TETRAHEDRON) | |
| 1565 | |
| 1566 static 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 | |
| 1604 static 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 | |
| 1729 static 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 | |
| 1840 static 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 | |
| 1961 static 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 */ | |
| 2062 void 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 */ | |
| 2071 void 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 */ | |
| 2081 void 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 */ | |
| 2090 void 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 */ | |
| 2100 void 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 */ | |
| 2109 void 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 */ | |
| 2118 void 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 */ | |
| 2127 void 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 | |
| 2149 void FGAPIENTRY glutWireCube( double dSize ) | |
| 2150 { | |
| 2151 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" ); | |
| 2152 fghCube( (GLfloat)dSize, GL_TRUE ); | |
| 2153 } | |
| 2154 void FGAPIENTRY glutSolidCube( double dSize ) | |
| 2155 { | |
| 2156 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" ); | |
| 2157 fghCube( (GLfloat)dSize, GL_FALSE ); | |
| 2158 } | |
| 2159 | |
| 2160 DECLARE_SHAPE_INTERFACE(Dodecahedron) | |
| 2161 DECLARE_SHAPE_INTERFACE(Icosahedron) | |
| 2162 DECLARE_SHAPE_INTERFACE(Octahedron) | |
| 2163 DECLARE_SHAPE_INTERFACE(RhombicDodecahedron) | |
| 2164 | |
| 2165 void 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 } | |
| 2170 void 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 | |
| 2176 DECLARE_SHAPE_INTERFACE(Tetrahedron) | |
| 2177 | |
| 2178 | |
| 2179 /*** END OF FILE ***/ |
