1 module DrawGL; 2 3 import gtkglc.gl; 4 import gtkglc.glu; 5 import gtkc.glibtypes; 6 7 version (Tango) 8 private import tango.math.Math; 9 else 10 private import std.math; 11 12 /* 13 * The following code is imported from GLUT. 14 * 15 * Adapted to D by Mike Wey, 2012. 16 * 17 * Copyright (c) Mark J. Kilgard, 1994, 1997. 18 * 19 * (c) Copyright 1993, Silicon Graphics, Inc. 20 * 21 * ALL RIGHTS RESERVED 22 * 23 * Permission to use, copy, modify, and distribute this software 24 * for any purpose and without fee is hereby granted, provided 25 * that the above copyright notice appear in all copies and that 26 * both the copyright notice and this permission notice appear in 27 * supporting documentation, and that the name of Silicon 28 * Graphics, Inc. not be used in advertising or publicity 29 * pertaining to distribution of the software without specific, 30 * written prior permission. 31 * 32 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU 33 * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR 34 * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF 35 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO 36 * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE 37 * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR 38 * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, 39 * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, 40 * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR 41 * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY 42 * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 43 * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR 44 * PERFORMANCE OF THIS SOFTWARE. 45 * 46 * US Government Users Restricted Rights 47 * 48 * Use, duplication, or disclosure by the Government is subject to 49 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph 50 * (c)(1)(ii) of the Rights in Technical Data and Computer 51 * Software clause at DFARS 252.227-7013 and/or in similar or 52 * successor clauses in the FAR or the DOD or NASA FAR 53 * Supplement. Unpublished-- rights reserved under the copyright 54 * laws of the United States. Contractor/manufacturer is Silicon 55 * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA 56 * 94039-7311. 57 * 58 * OpenGL(TM) is a trademark of Silicon Graphics, Inc. 59 */ 60 61 /* 62 * Cube 63 */ 64 65 static void drawBox(GLfloat size, GLenum type) 66 { 67 static GLfloat n[6][3] = 68 [ 69 [-1.0, 0.0, 0.0], 70 [0.0, 1.0, 0.0], 71 [1.0, 0.0, 0.0], 72 [0.0, -1.0, 0.0], 73 [0.0, 0.0, 1.0], 74 [0.0, 0.0, -1.0] 75 ]; 76 static GLint faces[6][4] = 77 [ 78 [0, 1, 2, 3], 79 [3, 2, 6, 7], 80 [7, 6, 5, 4], 81 [4, 5, 1, 0], 82 [5, 6, 2, 1], 83 [7, 4, 0, 3] 84 ]; 85 86 GLfloat v[8][3]; 87 GLint i; 88 89 v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2; 90 v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2; 91 v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2; 92 v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2; 93 v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2; 94 v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2; 95 96 for (i = 5; i >= 0; i--) { 97 glBegin(type); 98 glNormal3fv(&n[i][0]); 99 glVertex3fv(&v[faces[i][0]][0]); 100 glVertex3fv(&v[faces[i][1]][0]); 101 glVertex3fv(&v[faces[i][2]][0]); 102 glVertex3fv(&v[faces[i][3]][0]); 103 glEnd(); 104 } 105 } 106 107 /** 108 * Renders a cube. 109 * The cube is centered at the modeling coordinates origin with sides of 110 * length size. 111 * 112 * Params: 113 * solid = true if the cube should be solid. 114 * size = length of cube sides. 115 **/ 116 void drawCube(gboolean solid, double size) 117 { 118 if (solid) 119 drawBox (size, GL_QUADS); 120 else 121 drawBox (size, GL_LINE_LOOP); 122 } 123 124 /* 125 * Quadrics 126 */ 127 128 static GLUquadric* quadObj = null; 129 130 static void initQuadObj() 131 { 132 if ( quadObj !is null ) 133 return; 134 135 quadObj = gluNewQuadric(); 136 137 if (!quadObj) 138 throw new Error("out of memory."); 139 } 140 141 /** 142 * Renders a sphere centered at the modeling coordinates origin of 143 * the specified @radius. The sphere is subdivided around the Z axis into 144 * slices and along the Z axis into stacks. 145 * 146 * Params: 147 * solid = true if the sphere should be solid. 148 * radius = the radius of the sphere. 149 * slices = the number of subdivisions around the Z axis 150 * (similar to lines of longitude). 151 * stacks = the number of subdivisions along the Z axis 152 * (similar to lines of latitude). 153 **/ 154 void drawSphere(gboolean solid, double radius, int slices, int stacks) 155 { 156 initQuadObj(); 157 158 if (solid) 159 gluQuadricDrawStyle (quadObj, GLU_FILL); 160 else 161 gluQuadricDrawStyle (quadObj, GLU_LINE); 162 163 gluQuadricNormals (quadObj, GLU_SMOOTH); 164 165 /* If we ever changed/used the texture or orientation state 166 of quadObj, we'd need to change it to the defaults here 167 with gluQuadricTexture and/or gluQuadricOrientation. */ 168 gluSphere (quadObj, radius, slices, stacks); 169 } 170 171 /** 172 * Renders a cone oriented along the Z axis. 173 * The base of the cone is placed at Z = 0, and the top at Z = height. 174 * The cone is subdivided around the Z axis into slices, and along 175 * the Z axis into stacks. 176 * 177 * Params: 178 * solid = true if the cone should be solid. 179 * base = the radius of the base of the cone. 180 * height = the height of the cone. 181 * slices = the number of subdivisions around the Z axis. 182 * stacks = the number of subdivisions along the Z axis. 183 **/ 184 void drawCone(gboolean solid, double base, double height, int slices, int stacks) 185 { 186 initQuadObj(); 187 188 if (solid) 189 gluQuadricDrawStyle (quadObj, GLU_FILL); 190 else 191 gluQuadricDrawStyle (quadObj, GLU_LINE); 192 193 gluQuadricNormals (quadObj, GLU_SMOOTH); 194 195 /* If we ever changed/used the texture or orientation state 196 of quadObj, we'd need to change it to the defaults here 197 with gluQuadricTexture and/or gluQuadricOrientation. */ 198 gluCylinder (quadObj, base, 0.0, height, slices, stacks); 199 } 200 201 /* 202 * Torus 203 */ 204 205 static void doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings) 206 { 207 int i, j; 208 GLfloat theta, phi, theta1; 209 GLfloat cosTheta, sinTheta; 210 GLfloat cosTheta1, sinTheta1; 211 GLfloat ringDelta, sideDelta; 212 ringDelta = 2.0 * PI / rings; 213 sideDelta = 2.0 * PI / nsides; 214 215 theta = 0.0; 216 cosTheta = 1.0; 217 sinTheta = 0.0; 218 for (i = rings - 1; i >= 0; i--) { 219 theta1 = theta + ringDelta; 220 cosTheta1 = cos(theta1); 221 sinTheta1 = sin(theta1); 222 glBegin(GL_QUAD_STRIP); 223 phi = 0.0; 224 for (j = nsides; j >= 0; j--) { 225 GLfloat cosPhi, sinPhi, dist; 226 227 phi += sideDelta; 228 cosPhi = cos(phi); 229 sinPhi = sin(phi); 230 dist = R + r * cosPhi; 231 232 glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); 233 glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi); 234 glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); 235 glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi); 236 } 237 glEnd(); 238 theta = theta1; 239 cosTheta = cosTheta1; 240 sinTheta = sinTheta1; 241 } 242 } 243 244 /** 245 * Renders a torus (doughnut) centered at the modeling coordinates 246 * origin whose axis is aligned with the Z axis. 247 * 248 * Params: 249 * solid = true if the torus should be solid. 250 * inner_radius = inner radius of the torus. 251 * outer_radius = outer radius of the torus. 252 * nsides = number of sides for each radial section. 253 * rings = number of radial divisions for the torus. 254 **/ 255 void drawTorus (gboolean solid, double inner_radius, double outer_radius, int nsides, int rings) 256 { 257 if (solid) 258 { 259 doughnut (inner_radius, outer_radius, nsides, rings); 260 } 261 else 262 { 263 glPushAttrib (GL_POLYGON_BIT); 264 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); 265 doughnut (inner_radius, outer_radius, nsides, rings); 266 glPopAttrib (); 267 } 268 } 269 270 static void diff3(T, U, V)(T a, U b, ref V c) 271 { 272 c[0] = a[0] - b[0]; 273 c[1] = a[1] - b[1]; 274 c[2] = a[2] - b[2]; 275 } 276 277 278 static void crossprod(GLfloat[3] v1, GLfloat[3] v2, ref GLfloat[3] prod) 279 { 280 GLfloat p[3]; /* in case prod == v1 or v2 */ 281 282 p[0] = v1[1] * v2[2] - v2[1] * v1[2]; 283 p[1] = v1[2] * v2[0] - v2[2] * v1[0]; 284 p[2] = v1[0] * v2[1] - v2[0] * v1[1]; 285 prod[0] = p[0]; 286 prod[1] = p[1]; 287 prod[2] = p[2]; 288 } 289 290 static void normalize(ref GLfloat[3] v) 291 { 292 GLfloat d; 293 294 d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 295 if (d == 0.0) { 296 //g_warning("normalize: zero length vector"); 297 v[0] = d = 1.0; 298 } 299 d = 1 / d; 300 v[0] *= d; 301 v[1] *= d; 302 v[2] *= d; 303 } 304 305 static void recorditem(GLfloat[3] n1, GLfloat[3] n2, GLfloat[3] n3, GLenum shadeType) 306 { 307 GLfloat[3] q0, q1; 308 309 diff3(n1, n2, q0); 310 diff3(n2, n3, q1); 311 crossprod(q0, q1, q1); 312 normalize(q1); 313 314 glBegin(shadeType); 315 glNormal3fv(q1.ptr); 316 glVertex3fv(n1.ptr); 317 glVertex3fv(n2.ptr); 318 glVertex3fv(n3.ptr); 319 glEnd(); 320 } 321 322 static void subdivide(GLfloat[3] v0, GLfloat[3] v1, GLfloat[3] v2, GLenum shadeType) 323 { 324 int depth; 325 GLfloat[3] w0, w1, w2; 326 GLfloat l; 327 int i, j, k, n; 328 329 depth = 1; 330 for (i = 0; i < depth; i++) { 331 for (j = 0; i + j < depth; j++) { 332 k = depth - i - j; 333 for (n = 0; n < 3; n++) { 334 w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth; 335 w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n]) 336 / depth; 337 w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n]) 338 / depth; 339 } 340 l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]); 341 w0[0] /= l; 342 w0[1] /= l; 343 w0[2] /= l; 344 l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]); 345 w1[0] /= l; 346 w1[1] /= l; 347 w1[2] /= l; 348 l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]); 349 w2[0] /= l; 350 w2[1] /= l; 351 w2[2] /= l; 352 recorditem(w1, w0, w2, shadeType); 353 } 354 } 355 } 356 357 static void drawtriangle(int i, GLfloat[3][] data, int[3][] ndx, GLenum shadeType) 358 { 359 GLfloat[3] x0, x1, x2; 360 361 x0 = data[ndx[i][0]]; 362 x1 = data[ndx[i][1]]; 363 x2 = data[ndx[i][2]]; 364 subdivide(x0, x1, x2, shadeType); 365 } 366 367 /* 368 * Tetrahedron 369 */ 370 371 /* tetrahedron data: */ 372 373 const T = 1.73205080756887729; 374 375 static GLfloat tdata[4][3] = 376 [ 377 [T, T, T], 378 [T, -T, -T], 379 [-T, T, -T], 380 [-T, -T, T] 381 ]; 382 383 static int tndex[4][3] = 384 [ 385 [0, 1, 3], 386 [2, 1, 0], 387 [3, 2, 0], 388 [1, 2, 3] 389 ]; 390 391 static void tetrahedron(GLenum shadeType) 392 { 393 int i; 394 395 for (i = 3; i >= 0; i--) 396 drawtriangle(i, tdata, tndex, shadeType); 397 } 398 399 /** 400 * Renders a tetrahedron centered at the modeling coordinates 401 * origin with a radius of the square root of 3. 402 * 403 * Params: 404 * solid = true if the tetrahedron should be solid. 405 **/ 406 void drawTetrahedron (gboolean solid) 407 { 408 if (solid) 409 tetrahedron (GL_TRIANGLES); 410 else 411 tetrahedron (GL_LINE_LOOP); 412 } 413 414 /* 415 * Octahedron 416 */ 417 418 /* octahedron data: The octahedron produced is centered at the 419 origin and has radius 1.0 */ 420 static GLfloat odata[6][3] = 421 [ 422 [1.0, 0.0, 0.0], 423 [-1.0, 0.0, 0.0], 424 [0.0, 1.0, 0.0], 425 [0.0, -1.0, 0.0], 426 [0.0, 0.0, 1.0], 427 [0.0, 0.0, -1.0] 428 ]; 429 430 static int ondex[8][3] = 431 [ 432 [0, 4, 2], 433 [1, 2, 4], 434 [0, 3, 4], 435 [1, 4, 3], 436 [0, 2, 5], 437 [1, 5, 2], 438 [0, 5, 3], 439 [1, 3, 5] 440 ]; 441 442 static void octahedron(GLenum shadeType) 443 { 444 int i; 445 446 for (i = 7; i >= 0; i--) { 447 drawtriangle(i, odata, ondex, shadeType); 448 } 449 } 450 451 /** 452 * Renders a octahedron centered at the modeling coordinates 453 * origin with a radius of 1.0. 454 * 455 * Params: 456 * solid = true if the octahedron should be solid. 457 **/ 458 void drawOctahedron (gboolean solid) 459 { 460 if (solid) 461 octahedron (GL_TRIANGLES); 462 else 463 octahedron (GL_LINE_LOOP); 464 } 465 466 /* 467 * Icosahedron 468 */ 469 470 /* icosahedron data: These numbers are rigged to make an 471 icosahedron of radius 1.0 */ 472 473 const X = 0.525731112119133606; 474 const Z = 0.850650808352039932; 475 476 static GLfloat idata[12][3] = 477 [ 478 [-X, 0, Z], 479 [X, 0, Z], 480 [-X, 0, -Z], 481 [X, 0, -Z], 482 [0, Z, X], 483 [0, Z, -X], 484 [0, -Z, X], 485 [0, -Z, -X], 486 [Z, X, 0], 487 [-Z, X, 0], 488 [Z, -X, 0], 489 [-Z, -X, 0] 490 ]; 491 492 static int index[20][3] = 493 [ 494 [0, 4, 1], 495 [0, 9, 4], 496 [9, 5, 4], 497 [4, 5, 8], 498 [4, 8, 1], 499 [8, 10, 1], 500 [8, 3, 10], 501 [5, 3, 8], 502 [5, 2, 3], 503 [2, 7, 3], 504 [7, 10, 3], 505 [7, 6, 10], 506 [7, 11, 6], 507 [11, 0, 6], 508 [0, 1, 6], 509 [6, 1, 10], 510 [9, 0, 11], 511 [9, 11, 2], 512 [9, 2, 5], 513 [7, 2, 11], 514 ]; 515 516 static void icosahedron(GLenum shadeType) 517 { 518 int i; 519 520 for (i = 19; i >= 0; i--) { 521 drawtriangle(i, idata, index, shadeType); 522 } 523 } 524 525 /** 526 * Renders a icosahedron. 527 * The icosahedron is centered at the modeling coordinates origin 528 * and has a radius of 1.0. 529 * 530 * Params: 531 * solid = true if the icosahedron should be solid. 532 **/ 533 void drawIcosahedron (gboolean solid) 534 { 535 if (solid) 536 icosahedron (GL_TRIANGLES); 537 else 538 icosahedron (GL_LINE_LOOP); 539 } 540 541 /* 542 * Dodecahedron 543 */ 544 545 static GLfloat dodec[20][3]; 546 547 static void initDodecahedron() 548 { 549 GLfloat alpha, beta; 550 551 alpha = sqrt(2.0 / (3.0 + sqrt(5.0))); 552 beta = 1.0 + sqrt(6.0 / (3.0 + sqrt(5.0)) - 553 2.0 + 2.0 * sqrt(2.0 / (3.0 + sqrt(5.0)))); 554 /* *INDENT-OFF* */ 555 dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta; 556 dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta; 557 dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1; 558 dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1; 559 dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1; 560 dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1; 561 dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1; 562 dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1; 563 dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1; 564 dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1; 565 dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0; 566 dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0; 567 dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0; 568 dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0; 569 dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta; 570 dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta; 571 dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha; 572 dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha; 573 dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha; 574 dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha; 575 /* *INDENT-ON* */ 576 577 } 578 579 static void pentagon(int a, int b, int c, int d, int e, GLenum shadeType) 580 { 581 GLfloat[3] n0, d1, d2; 582 583 diff3(dodec[a], dodec[b], d1); 584 diff3(dodec[b], dodec[c], d2); 585 crossprod(d1, d2, n0); 586 normalize(n0); 587 588 glBegin(shadeType); 589 glNormal3fv(n0.ptr); 590 glVertex3fv(&dodec[a][0]); 591 glVertex3fv(&dodec[b][0]); 592 glVertex3fv(&dodec[c][0]); 593 glVertex3fv(&dodec[d][0]); 594 glVertex3fv(&dodec[e][0]); 595 glEnd(); 596 } 597 598 static void dodecahedron(GLenum type) 599 { 600 static int inited = 0; 601 602 if (inited == 0) { 603 inited = 1; 604 initDodecahedron(); 605 } 606 pentagon(0, 1, 9, 16, 5, type); 607 pentagon(1, 0, 3, 18, 7, type); 608 pentagon(1, 7, 11, 10, 9, type); 609 pentagon(11, 7, 18, 19, 6, type); 610 pentagon(8, 17, 16, 9, 10, type); 611 pentagon(2, 14, 15, 6, 19, type); 612 pentagon(2, 13, 12, 4, 14, type); 613 pentagon(2, 19, 18, 3, 13, type); 614 pentagon(3, 0, 5, 12, 13, type); 615 pentagon(6, 15, 8, 10, 11, type); 616 pentagon(4, 17, 8, 15, 14, type); 617 pentagon(4, 12, 5, 16, 17, type); 618 } 619 620 /** 621 * Renders a dodecahedron centered at the modeling coordinates 622 * origin with a radius of the square root of 3. 623 * 624 * Params: 625 * solid = true if the dodecahedron should be solid. 626 **/ 627 void drawDodecahedron (gboolean solid) 628 { 629 if (solid) 630 dodecahedron (GL_TRIANGLE_FAN); 631 else 632 dodecahedron (GL_LINE_LOOP); 633 } 634 635 /* 636 * Teapot 637 */ 638 639 /* Rim, body, lid, and bottom data must be reflected in x and 640 y; handle and spout data across the y axis only. */ 641 642 static int patchdata[][16] = 643 [ 644 /* rim */ 645 [102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 646 12, 13, 14, 15], 647 /* body */ 648 [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 649 24, 25, 26, 27], 650 [24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 651 37, 38, 39, 40], 652 /* lid */ 653 [96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 654 101, 0, 1, 2, 3,], 655 [0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 656 113, 114, 115, 116, 117], 657 /* bottom */ 658 [118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 659 125, 120, 40, 39, 38, 37], 660 /* handle */ 661 [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 662 53, 54, 55, 56], 663 [53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 664 28, 65, 66, 67], 665 /* spout */ 666 [68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 667 80, 81, 82, 83], 668 [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 669 92, 93, 94, 95] 670 ]; 671 /* *INDENT-OFF* */ 672 673 static float cpdata[][3] = 674 [ 675 [0.2, 0, 2.7], [0.2, -0.112, 2.7], [0.112, -0.2, 2.7], [0, 676 -0.2, 2.7], [1.3375, 0, 2.53125], [1.3375, -0.749, 2.53125], 677 [0.749, -1.3375, 2.53125], [0, -1.3375, 2.53125], [1.4375, 678 0, 2.53125], [1.4375, -0.805, 2.53125], [0.805, -1.4375, 679 2.53125], [0, -1.4375, 2.53125], [1.5, 0, 2.4], [1.5, -0.84, 680 2.4], [0.84, -1.5, 2.4], [0, -1.5, 2.4], [1.75, 0, 1.875], 681 [1.75, -0.98, 1.875], [0.98, -1.75, 1.875], [0, -1.75, 682 1.875], [2, 0, 1.35], [2, -1.12, 1.35], [1.12, -2, 1.35], 683 [0, -2, 1.35], [2, 0, 0.9], [2, -1.12, 0.9], [1.12, -2, 684 0.9], [0, -2, 0.9], [-2, 0, 0.9], [2, 0, 0.45], [2, -1.12, 685 0.45], [1.12, -2, 0.45], [0, -2, 0.45], [1.5, 0, 0.225], 686 [1.5, -0.84, 0.225], [0.84, -1.5, 0.225], [0, -1.5, 0.225], 687 [1.5, 0, 0.15], [1.5, -0.84, 0.15], [0.84, -1.5, 0.15], [0, 688 -1.5, 0.15], [-1.6, 0, 2.025], [-1.6, -0.3, 2.025], [-1.5, 689 -0.3, 2.25], [-1.5, 0, 2.25], [-2.3, 0, 2.025], [-2.3, -0.3, 690 2.025], [-2.5, -0.3, 2.25], [-2.5, 0, 2.25], [-2.7, 0, 691 2.025], [-2.7, -0.3, 2.025], [-3, -0.3, 2.25], [-3, 0, 692 2.25], [-2.7, 0, 1.8], [-2.7, -0.3, 1.8], [-3, -0.3, 1.8], 693 [-3, 0, 1.8], [-2.7, 0, 1.575], [-2.7, -0.3, 1.575], [-3, 694 -0.3, 1.35], [-3, 0, 1.35], [-2.5, 0, 1.125], [-2.5, -0.3, 695 1.125], [-2.65, -0.3, 0.9375], [-2.65, 0, 0.9375], [-2, 696 -0.3, 0.9], [-1.9, -0.3, 0.6], [-1.9, 0, 0.6], [1.7, 0, 697 1.425], [1.7, -0.66, 1.425], [1.7, -0.66, 0.6], [1.7, 0, 698 0.6], [2.6, 0, 1.425], [2.6, -0.66, 1.425], [3.1, -0.66, 699 0.825], [3.1, 0, 0.825], [2.3, 0, 2.1], [2.3, -0.25, 2.1], 700 [2.4, -0.25, 2.025], [2.4, 0, 2.025], [2.7, 0, 2.4], [2.7, 701 -0.25, 2.4], [3.3, -0.25, 2.4], [3.3, 0, 2.4], [2.8, 0, 702 2.475], [2.8, -0.25, 2.475], [3.525, -0.25, 2.49375], 703 [3.525, 0, 2.49375], [2.9, 0, 2.475], [2.9, -0.15, 2.475], 704 [3.45, -0.15, 2.5125], [3.45, 0, 2.5125], [2.8, 0, 2.4], 705 [2.8, -0.15, 2.4], [3.2, -0.15, 2.4], [3.2, 0, 2.4], [0, 0, 706 3.15], [0.8, 0, 3.15], [0.8, -0.45, 3.15], [0.45, -0.8, 707 3.15], [0, -0.8, 3.15], [0, 0, 2.85], [1.4, 0, 2.4], [1.4, 708 -0.784, 2.4], [0.784, -1.4, 2.4], [0, -1.4, 2.4], [0.4, 0, 709 2.55], [0.4, -0.224, 2.55], [0.224, -0.4, 2.55], [0, -0.4, 710 2.55], [1.3, 0, 2.55], [1.3, -0.728, 2.55], [0.728, -1.3, 711 2.55], [0, -1.3, 2.55], [1.3, 0, 2.4], [1.3, -0.728, 2.4], 712 [0.728, -1.3, 2.4], [0, -1.3, 2.4], [0, 0, 0], [1.425, 713 -0.798, 0], [1.5, 0, 0.075], [1.425, 0, 0], [0.798, -1.425, 714 0], [0, -1.5, 0.075], [0, -1.425, 0], [1.5, -0.84, 0.075], 715 [0.84, -1.5, 0.075] 716 ]; 717 718 static float tex[2][2][2] = 719 [ 720 [ [0, 0], 721 [1, 0]], 722 [ [0, 1], 723 [1, 1]] 724 ]; 725 726 /* *INDENT-ON* */ 727 728 static void teapot(GLint grid, GLdouble scale, GLenum type) 729 { 730 float[3][4][4] p, q, r, s; 731 long i, j, k, l; 732 733 glPushAttrib(GL_ENABLE_BIT | GL_EVAL_BIT); 734 glEnable(GL_AUTO_NORMAL); 735 glEnable(GL_NORMALIZE); 736 glEnable(GL_MAP2_VERTEX_3); 737 glEnable(GL_MAP2_TEXTURE_COORD_2); 738 glPushMatrix(); 739 glRotatef(270.0, 1.0, 0.0, 0.0); 740 glScalef(0.5 * scale, 0.5 * scale, 0.5 * scale); 741 glTranslatef(0.0, 0.0, -1.5); 742 for (i = 0; i < 10; i++) { 743 for (j = 0; j < 4; j++) { 744 for (k = 0; k < 4; k++) { 745 for (l = 0; l < 3; l++) { 746 p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; 747 q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; 748 if (l == 1) 749 q[j][k][l] *= -1.0; 750 if (i < 6) { 751 r[j][k][l] = 752 cpdata[patchdata[i][j * 4 + (3 - k)]][l]; 753 if (l == 0) 754 r[j][k][l] *= -1.0; 755 s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; 756 if (l == 0) 757 s[j][k][l] *= -1.0; 758 if (l == 1) 759 s[j][k][l] *= -1.0; 760 } 761 } 762 } 763 } 764 glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &tex[0][0][0]); 765 glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &p[0][0][0]); 766 glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0); 767 glEvalMesh2(type, 0, grid, 0, grid); 768 glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &q[0][0][0]); 769 glEvalMesh2(type, 0, grid, 0, grid); 770 if (i < 6) { 771 glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &r[0][0][0]); 772 glEvalMesh2(type, 0, grid, 0, grid); 773 glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &s[0][0][0]); 774 glEvalMesh2(type, 0, grid, 0, grid); 775 } 776 } 777 glPopMatrix(); 778 glPopAttrib(); 779 } 780 781 /** 782 * Renders a teapot. 783 * Both surface normals and texture coordinates for the teapot are generated. 784 * The teapot is generated with OpenGL evaluators. 785 * 786 * Params: 787 * solid = true if the teapot should be solid. 788 * scale = relative size of the teapot. 789 **/ 790 void drawTeapot (gboolean solid, double scale) 791 { 792 if (solid) 793 teapot (7, scale, GL_FILL); 794 else 795 teapot (10, scale, GL_LINE); 796 }