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