1 /* 2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice including the dates of first publication and 13 * either this permission notice or a reference to 14 * http://oss.sgi.com/projects/FreeB/ 15 * shall be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Except as contained in this notice, the name of Silicon Graphics, Inc. 26 * shall not be used in advertising or otherwise to promote the sale, use or 27 * other dealings in this Software without prior written authorization from 28 * Silicon Graphics, Inc. 29 */ 30 31 #include "gluos.h" 32 #include "gluint.h" 33 //#include <stdio.h> 34 //#include <stdlib.h> 35 #include <math.h> 36 //#include <GL/gl.h> 37 #include <GL/glu.h> 38 39 /* Make it not a power of two to avoid cache thrashing on the chip */ 40 #define CACHE_SIZE 240 41 42 #undef PI 43 #define PI 3.14159265358979323846 44 45 struct GLUquadric { 46 GLint normals; 47 GLboolean textureCoords; 48 GLint orientation; 49 GLint drawStyle; 50 void (GLAPIENTRY *errorCallback)( GLint ); 51 }; 52 53 GLUquadric * GLAPIENTRY 54 gluNewQuadric(void) 55 { 56 GLUquadric *newstate; 57 58 newstate = (GLUquadric *) malloc(sizeof(GLUquadric)); 59 if (newstate == NULL) { 60 /* Can't report an error at this point... */ 61 return NULL; 62 } 63 newstate->normals = GLU_SMOOTH; 64 newstate->textureCoords = GL_FALSE; 65 newstate->orientation = GLU_OUTSIDE; 66 newstate->drawStyle = GLU_FILL; 67 newstate->errorCallback = NULL; 68 return newstate; 69 } 70 71 72 void GLAPIENTRY 73 gluDeleteQuadric(GLUquadric *state) 74 { 75 free(state); 76 } 77 78 static void gluQuadricError(GLUquadric *qobj, GLenum which) 79 { 80 if (qobj->errorCallback) { 81 qobj->errorCallback(which); 82 } 83 } 84 85 void GLAPIENTRY 86 gluQuadricCallback(GLUquadric *qobj, GLenum which, _GLUfuncptr fn) 87 { 88 switch (which) { 89 case GLU_ERROR: 90 qobj->errorCallback = (void (GLAPIENTRY *)(GLint)) fn; 91 break; 92 default: 93 gluQuadricError(qobj, GLU_INVALID_ENUM); 94 return; 95 } 96 } 97 98 void GLAPIENTRY 99 gluQuadricNormals(GLUquadric *qobj, GLenum normals) 100 { 101 switch (normals) { 102 case GLU_SMOOTH: 103 case GLU_FLAT: 104 case GLU_NONE: 105 break; 106 default: 107 gluQuadricError(qobj, GLU_INVALID_ENUM); 108 return; 109 } 110 qobj->normals = normals; 111 } 112 113 void GLAPIENTRY 114 gluQuadricTexture(GLUquadric *qobj, GLboolean textureCoords) 115 { 116 qobj->textureCoords = textureCoords; 117 } 118 119 void GLAPIENTRY 120 gluQuadricOrientation(GLUquadric *qobj, GLenum orientation) 121 { 122 switch(orientation) { 123 case GLU_OUTSIDE: 124 case GLU_INSIDE: 125 break; 126 default: 127 gluQuadricError(qobj, GLU_INVALID_ENUM); 128 return; 129 } 130 qobj->orientation = orientation; 131 } 132 133 void GLAPIENTRY 134 gluQuadricDrawStyle(GLUquadric *qobj, GLenum drawStyle) 135 { 136 switch(drawStyle) { 137 case GLU_POINT: 138 case GLU_LINE: 139 case GLU_FILL: 140 case GLU_SILHOUETTE: 141 break; 142 default: 143 gluQuadricError(qobj, GLU_INVALID_ENUM); 144 return; 145 } 146 qobj->drawStyle = drawStyle; 147 } 148 149 void GLAPIENTRY 150 gluCylinder(GLUquadric *qobj, GLdouble baseRadius, GLdouble topRadius, 151 GLdouble height, GLint slices, GLint stacks) 152 { 153 GLint i,j; 154 GLfloat sinCache[CACHE_SIZE]; 155 GLfloat cosCache[CACHE_SIZE]; 156 GLfloat sinCache2[CACHE_SIZE]; 157 GLfloat cosCache2[CACHE_SIZE]; 158 GLfloat sinCache3[CACHE_SIZE]; 159 GLfloat cosCache3[CACHE_SIZE]; 160 GLfloat angle; 161 GLfloat zLow, zHigh; 162 GLfloat sintemp, costemp; 163 GLfloat length; 164 GLfloat deltaRadius; 165 GLfloat zNormal; 166 GLfloat xyNormalRatio; 167 GLfloat radiusLow, radiusHigh; 168 int needCache2, needCache3; 169 170 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1; 171 172 if (slices < 2 || stacks < 1 || baseRadius < 0.0 || topRadius < 0.0 || 173 height < 0.0) { 174 gluQuadricError(qobj, GLU_INVALID_VALUE); 175 return; 176 } 177 178 /* Compute length (needed for normal calculations) */ 179 deltaRadius = baseRadius - topRadius; 180 length = SQRT(deltaRadius*deltaRadius + height*height); 181 if (length == 0.0) { 182 gluQuadricError(qobj, GLU_INVALID_VALUE); 183 return; 184 } 185 186 /* Cache is the vertex locations cache */ 187 /* Cache2 is the various normals at the vertices themselves */ 188 /* Cache3 is the various normals for the faces */ 189 needCache2 = needCache3 = 0; 190 if (qobj->normals == GLU_SMOOTH) { 191 needCache2 = 1; 192 } 193 194 if (qobj->normals == GLU_FLAT) { 195 if (qobj->drawStyle != GLU_POINT) { 196 needCache3 = 1; 197 } 198 if (qobj->drawStyle == GLU_LINE) { 199 needCache2 = 1; 200 } 201 } 202 203 zNormal = deltaRadius / length; 204 xyNormalRatio = height / length; 205 206 for (i = 0; i < slices; i++) { 207 angle = 2 * PI * i / slices; 208 if (needCache2) { 209 if (qobj->orientation == GLU_OUTSIDE) { 210 sinCache2[i] = xyNormalRatio * SIN(angle); 211 cosCache2[i] = xyNormalRatio * COS(angle); 212 } else { 213 sinCache2[i] = -xyNormalRatio * SIN(angle); 214 cosCache2[i] = -xyNormalRatio * COS(angle); 215 } 216 } 217 sinCache[i] = SIN(angle); 218 cosCache[i] = COS(angle); 219 } 220 221 if (needCache3) { 222 for (i = 0; i < slices; i++) { 223 angle = 2 * PI * (i-0.5) / slices; 224 if (qobj->orientation == GLU_OUTSIDE) { 225 sinCache3[i] = xyNormalRatio * SIN(angle); 226 cosCache3[i] = xyNormalRatio * COS(angle); 227 } else { 228 sinCache3[i] = -xyNormalRatio * SIN(angle); 229 cosCache3[i] = -xyNormalRatio * COS(angle); 230 } 231 } 232 } 233 234 sinCache[slices] = sinCache[0]; 235 cosCache[slices] = cosCache[0]; 236 if (needCache2) { 237 sinCache2[slices] = sinCache2[0]; 238 cosCache2[slices] = cosCache2[0]; 239 } 240 if (needCache3) { 241 sinCache3[slices] = sinCache3[0]; 242 cosCache3[slices] = cosCache3[0]; 243 } 244 245 switch (qobj->drawStyle) { 246 case GLU_FILL: 247 /* Note: 248 ** An argument could be made for using a TRIANGLE_FAN for the end 249 ** of the cylinder of either radii is 0.0 (a cone). However, a 250 ** TRIANGLE_FAN would not work in smooth shading mode (the common 251 ** case) because the normal for the apex is different for every 252 ** triangle (and TRIANGLE_FAN doesn't let me respecify that normal). 253 ** Now, my choice is GL_TRIANGLES, or leave the GL_QUAD_STRIP and 254 ** just let the GL trivially reject one of the two triangles of the 255 ** QUAD. GL_QUAD_STRIP is probably faster, so I will leave this code 256 ** alone. 257 */ 258 for (j = 0; j < stacks; j++) { 259 zLow = j * height / stacks; 260 zHigh = (j + 1) * height / stacks; 261 radiusLow = baseRadius - deltaRadius * ((float) j / stacks); 262 radiusHigh = baseRadius - deltaRadius * ((float) (j + 1) / stacks); 263 264 glBegin(GL_QUAD_STRIP); 265 for (i = 0; i <= slices; i++) { 266 switch(qobj->normals) { 267 case GLU_FLAT: 268 glNormal3f(sinCache3[i], cosCache3[i], zNormal); 269 break; 270 case GLU_SMOOTH: 271 glNormal3f(sinCache2[i], cosCache2[i], zNormal); 272 break; 273 case GLU_NONE: 274 default: 275 break; 276 } 277 if (qobj->orientation == GLU_OUTSIDE) { 278 if (qobj->textureCoords) { 279 glTexCoord2f(1 - (float) i / slices, 280 (float) j / stacks); 281 } 282 glVertex3f(radiusLow * sinCache[i], 283 radiusLow * cosCache[i], zLow); 284 if (qobj->textureCoords) { 285 glTexCoord2f(1 - (float) i / slices, 286 (float) (j+1) / stacks); 287 } 288 glVertex3f(radiusHigh * sinCache[i], 289 radiusHigh * cosCache[i], zHigh); 290 } else { 291 if (qobj->textureCoords) { 292 glTexCoord2f(1 - (float) i / slices, 293 (float) (j+1) / stacks); 294 } 295 glVertex3f(radiusHigh * sinCache[i], 296 radiusHigh * cosCache[i], zHigh); 297 if (qobj->textureCoords) { 298 glTexCoord2f(1 - (float) i / slices, 299 (float) j / stacks); 300 } 301 glVertex3f(radiusLow * sinCache[i], 302 radiusLow * cosCache[i], zLow); 303 } 304 } 305 glEnd(); 306 } 307 break; 308 case GLU_POINT: 309 glBegin(GL_POINTS); 310 for (i = 0; i < slices; i++) { 311 switch(qobj->normals) { 312 case GLU_FLAT: 313 case GLU_SMOOTH: 314 glNormal3f(sinCache2[i], cosCache2[i], zNormal); 315 break; 316 case GLU_NONE: 317 default: 318 break; 319 } 320 sintemp = sinCache[i]; 321 costemp = cosCache[i]; 322 for (j = 0; j <= stacks; j++) { 323 zLow = j * height / stacks; 324 radiusLow = baseRadius - deltaRadius * ((float) j / stacks); 325 326 if (qobj->textureCoords) { 327 glTexCoord2f(1 - (float) i / slices, 328 (float) j / stacks); 329 } 330 glVertex3f(radiusLow * sintemp, 331 radiusLow * costemp, zLow); 332 } 333 } 334 glEnd(); 335 break; 336 case GLU_LINE: 337 for (j = 1; j < stacks; j++) { 338 zLow = j * height / stacks; 339 radiusLow = baseRadius - deltaRadius * ((float) j / stacks); 340 341 glBegin(GL_LINE_STRIP); 342 for (i = 0; i <= slices; i++) { 343 switch(qobj->normals) { 344 case GLU_FLAT: 345 glNormal3f(sinCache3[i], cosCache3[i], zNormal); 346 break; 347 case GLU_SMOOTH: 348 glNormal3f(sinCache2[i], cosCache2[i], zNormal); 349 break; 350 case GLU_NONE: 351 default: 352 break; 353 } 354 if (qobj->textureCoords) { 355 glTexCoord2f(1 - (float) i / slices, 356 (float) j / stacks); 357 } 358 glVertex3f(radiusLow * sinCache[i], 359 radiusLow * cosCache[i], zLow); 360 } 361 glEnd(); 362 } 363 /* Intentionally fall through here... */ 364 case GLU_SILHOUETTE: 365 for (j = 0; j <= stacks; j += stacks) { 366 zLow = j * height / stacks; 367 radiusLow = baseRadius - deltaRadius * ((float) j / stacks); 368 369 glBegin(GL_LINE_STRIP); 370 for (i = 0; i <= slices; i++) { 371 switch(qobj->normals) { 372 case GLU_FLAT: 373 glNormal3f(sinCache3[i], cosCache3[i], zNormal); 374 break; 375 case GLU_SMOOTH: 376 glNormal3f(sinCache2[i], cosCache2[i], zNormal); 377 break; 378 case GLU_NONE: 379 default: 380 break; 381 } 382 if (qobj->textureCoords) { 383 glTexCoord2f(1 - (float) i / slices, 384 (float) j / stacks); 385 } 386 glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i], 387 zLow); 388 } 389 glEnd(); 390 } 391 for (i = 0; i < slices; i++) { 392 switch(qobj->normals) { 393 case GLU_FLAT: 394 case GLU_SMOOTH: 395 glNormal3f(sinCache2[i], cosCache2[i], 0.0); 396 break; 397 case GLU_NONE: 398 default: 399 break; 400 } 401 sintemp = sinCache[i]; 402 costemp = cosCache[i]; 403 glBegin(GL_LINE_STRIP); 404 for (j = 0; j <= stacks; j++) { 405 zLow = j * height / stacks; 406 radiusLow = baseRadius - deltaRadius * ((float) j / stacks); 407 408 if (qobj->textureCoords) { 409 glTexCoord2f(1 - (float) i / slices, 410 (float) j / stacks); 411 } 412 glVertex3f(radiusLow * sintemp, 413 radiusLow * costemp, zLow); 414 } 415 glEnd(); 416 } 417 break; 418 default: 419 break; 420 } 421 } 422 423 void GLAPIENTRY 424 gluDisk(GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius, 425 GLint slices, GLint loops) 426 { 427 gluPartialDisk(qobj, innerRadius, outerRadius, slices, loops, 0.0, 360.0); 428 } 429 430 void GLAPIENTRY 431 gluPartialDisk(GLUquadric *qobj, GLdouble innerRadius, 432 GLdouble outerRadius, GLint slices, GLint loops, 433 GLdouble startAngle, GLdouble sweepAngle) 434 { 435 GLint i,j; 436 GLfloat sinCache[CACHE_SIZE]; 437 GLfloat cosCache[CACHE_SIZE]; 438 GLfloat angle; 439 GLfloat sintemp, costemp; 440 GLfloat deltaRadius; 441 GLfloat radiusLow, radiusHigh; 442 GLfloat texLow = 0.0, texHigh = 0.0; 443 GLfloat angleOffset; 444 GLint slices2; 445 GLint finish; 446 447 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1; 448 if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 || 449 innerRadius > outerRadius) { 450 gluQuadricError(qobj, GLU_INVALID_VALUE); 451 return; 452 } 453 454 if (sweepAngle < -360.0) sweepAngle = 360.0; 455 if (sweepAngle > 360.0) sweepAngle = 360.0; 456 if (sweepAngle < 0) { 457 startAngle += sweepAngle; 458 sweepAngle = -sweepAngle; 459 } 460 461 if (sweepAngle == 360.0) { 462 slices2 = slices; 463 } else { 464 slices2 = slices + 1; 465 } 466 467 /* Compute length (needed for normal calculations) */ 468 deltaRadius = outerRadius - innerRadius; 469 470 /* Cache is the vertex locations cache */ 471 472 angleOffset = startAngle / 180.0 * PI; 473 for (i = 0; i <= slices; i++) { 474 angle = angleOffset + ((PI * sweepAngle) / 180.0) * i / slices; 475 sinCache[i] = SIN(angle); 476 cosCache[i] = COS(angle); 477 } 478 479 if (sweepAngle == 360.0) { 480 sinCache[slices] = sinCache[0]; 481 cosCache[slices] = cosCache[0]; 482 } 483 484 switch(qobj->normals) { 485 case GLU_FLAT: 486 case GLU_SMOOTH: 487 if (qobj->orientation == GLU_OUTSIDE) { 488 glNormal3f(0.0, 0.0, 1.0); 489 } else { 490 glNormal3f(0.0, 0.0, -1.0); 491 } 492 break; 493 default: 494 case GLU_NONE: 495 break; 496 } 497 498 switch (qobj->drawStyle) { 499 case GLU_FILL: 500 if (innerRadius == 0.0) { 501 finish = loops - 1; 502 /* Triangle strip for inner polygons */ 503 glBegin(GL_TRIANGLE_FAN); 504 if (qobj->textureCoords) { 505 glTexCoord2f(0.5, 0.5); 506 } 507 glVertex3f(0.0, 0.0, 0.0); 508 radiusLow = outerRadius - 509 deltaRadius * ((float) (loops-1) / loops); 510 if (qobj->textureCoords) { 511 texLow = radiusLow / outerRadius / 2; 512 } 513 514 if (qobj->orientation == GLU_OUTSIDE) { 515 for (i = slices; i >= 0; i--) { 516 if (qobj->textureCoords) { 517 glTexCoord2f(texLow * sinCache[i] + 0.5, 518 texLow * cosCache[i] + 0.5); 519 } 520 glVertex3f(radiusLow * sinCache[i], 521 radiusLow * cosCache[i], 0.0); 522 } 523 } else { 524 for (i = 0; i <= slices; i++) { 525 if (qobj->textureCoords) { 526 glTexCoord2f(texLow * sinCache[i] + 0.5, 527 texLow * cosCache[i] + 0.5); 528 } 529 glVertex3f(radiusLow * sinCache[i], 530 radiusLow * cosCache[i], 0.0); 531 } 532 } 533 glEnd(); 534 } else { 535 finish = loops; 536 } 537 for (j = 0; j < finish; j++) { 538 radiusLow = outerRadius - deltaRadius * ((float) j / loops); 539 radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops); 540 if (qobj->textureCoords) { 541 texLow = radiusLow / outerRadius / 2; 542 texHigh = radiusHigh / outerRadius / 2; 543 } 544 545 glBegin(GL_QUAD_STRIP); 546 for (i = 0; i <= slices; i++) { 547 if (qobj->orientation == GLU_OUTSIDE) { 548 if (qobj->textureCoords) { 549 glTexCoord2f(texLow * sinCache[i] + 0.5, 550 texLow * cosCache[i] + 0.5); 551 } 552 glVertex3f(radiusLow * sinCache[i], 553 radiusLow * cosCache[i], 0.0); 554 555 if (qobj->textureCoords) { 556 glTexCoord2f(texHigh * sinCache[i] + 0.5, 557 texHigh * cosCache[i] + 0.5); 558 } 559 glVertex3f(radiusHigh * sinCache[i], 560 radiusHigh * cosCache[i], 0.0); 561 } else { 562 if (qobj->textureCoords) { 563 glTexCoord2f(texHigh * sinCache[i] + 0.5, 564 texHigh * cosCache[i] + 0.5); 565 } 566 glVertex3f(radiusHigh * sinCache[i], 567 radiusHigh * cosCache[i], 0.0); 568 569 if (qobj->textureCoords) { 570 glTexCoord2f(texLow * sinCache[i] + 0.5, 571 texLow * cosCache[i] + 0.5); 572 } 573 glVertex3f(radiusLow * sinCache[i], 574 radiusLow * cosCache[i], 0.0); 575 } 576 } 577 glEnd(); 578 } 579 break; 580 case GLU_POINT: 581 glBegin(GL_POINTS); 582 for (i = 0; i < slices2; i++) { 583 sintemp = sinCache[i]; 584 costemp = cosCache[i]; 585 for (j = 0; j <= loops; j++) { 586 radiusLow = outerRadius - deltaRadius * ((float) j / loops); 587 588 if (qobj->textureCoords) { 589 texLow = radiusLow / outerRadius / 2; 590 591 glTexCoord2f(texLow * sinCache[i] + 0.5, 592 texLow * cosCache[i] + 0.5); 593 } 594 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0); 595 } 596 } 597 glEnd(); 598 break; 599 case GLU_LINE: 600 if (innerRadius == outerRadius) { 601 glBegin(GL_LINE_STRIP); 602 603 for (i = 0; i <= slices; i++) { 604 if (qobj->textureCoords) { 605 glTexCoord2f(sinCache[i] / 2 + 0.5, 606 cosCache[i] / 2 + 0.5); 607 } 608 glVertex3f(innerRadius * sinCache[i], 609 innerRadius * cosCache[i], 0.0); 610 } 611 glEnd(); 612 break; 613 } 614 for (j = 0; j <= loops; j++) { 615 radiusLow = outerRadius - deltaRadius * ((float) j / loops); 616 if (qobj->textureCoords) { 617 texLow = radiusLow / outerRadius / 2; 618 } 619 620 glBegin(GL_LINE_STRIP); 621 for (i = 0; i <= slices; i++) { 622 if (qobj->textureCoords) { 623 glTexCoord2f(texLow * sinCache[i] + 0.5, 624 texLow * cosCache[i] + 0.5); 625 } 626 glVertex3f(radiusLow * sinCache[i], 627 radiusLow * cosCache[i], 0.0); 628 } 629 glEnd(); 630 } 631 for (i=0; i < slices2; i++) { 632 sintemp = sinCache[i]; 633 costemp = cosCache[i]; 634 glBegin(GL_LINE_STRIP); 635 for (j = 0; j <= loops; j++) { 636 radiusLow = outerRadius - deltaRadius * ((float) j / loops); 637 if (qobj->textureCoords) { 638 texLow = radiusLow / outerRadius / 2; 639 } 640 641 if (qobj->textureCoords) { 642 glTexCoord2f(texLow * sinCache[i] + 0.5, 643 texLow * cosCache[i] + 0.5); 644 } 645 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0); 646 } 647 glEnd(); 648 } 649 break; 650 case GLU_SILHOUETTE: 651 if (sweepAngle < 360.0) { 652 for (i = 0; i <= slices; i+= slices) { 653 sintemp = sinCache[i]; 654 costemp = cosCache[i]; 655 glBegin(GL_LINE_STRIP); 656 for (j = 0; j <= loops; j++) { 657 radiusLow = outerRadius - deltaRadius * ((float) j / loops); 658 659 if (qobj->textureCoords) { 660 texLow = radiusLow / outerRadius / 2; 661 glTexCoord2f(texLow * sinCache[i] + 0.5, 662 texLow * cosCache[i] + 0.5); 663 } 664 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0); 665 } 666 glEnd(); 667 } 668 } 669 for (j = 0; j <= loops; j += loops) { 670 radiusLow = outerRadius - deltaRadius * ((float) j / loops); 671 if (qobj->textureCoords) { 672 texLow = radiusLow / outerRadius / 2; 673 } 674 675 glBegin(GL_LINE_STRIP); 676 for (i = 0; i <= slices; i++) { 677 if (qobj->textureCoords) { 678 glTexCoord2f(texLow * sinCache[i] + 0.5, 679 texLow * cosCache[i] + 0.5); 680 } 681 glVertex3f(radiusLow * sinCache[i], 682 radiusLow * cosCache[i], 0.0); 683 } 684 glEnd(); 685 if (innerRadius == outerRadius) break; 686 } 687 break; 688 default: 689 break; 690 } 691 } 692 693 void GLAPIENTRY 694 gluSphere(GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks) 695 { 696 GLint i,j; 697 GLfloat sinCache1a[CACHE_SIZE]; 698 GLfloat cosCache1a[CACHE_SIZE]; 699 GLfloat sinCache2a[CACHE_SIZE]; 700 GLfloat cosCache2a[CACHE_SIZE]; 701 GLfloat sinCache3a[CACHE_SIZE]; 702 GLfloat cosCache3a[CACHE_SIZE]; 703 GLfloat sinCache1b[CACHE_SIZE]; 704 GLfloat cosCache1b[CACHE_SIZE]; 705 GLfloat sinCache2b[CACHE_SIZE]; 706 GLfloat cosCache2b[CACHE_SIZE]; 707 GLfloat sinCache3b[CACHE_SIZE]; 708 GLfloat cosCache3b[CACHE_SIZE]; 709 GLfloat angle; 710 GLfloat zLow, zHigh; 711 GLfloat sintemp1 = 0.0, sintemp2 = 0.0, sintemp3 = 0.0, sintemp4 = 0.0; 712 GLfloat costemp1 = 0.0, costemp2 = 0.0, costemp3 = 0.0, costemp4 = 0.0; 713 GLboolean needCache2, needCache3; 714 GLint start, finish; 715 716 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1; 717 if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1; 718 if (slices < 2 || stacks < 1 || radius < 0.0) { 719 gluQuadricError(qobj, GLU_INVALID_VALUE); 720 return; 721 } 722 723 /* Cache is the vertex locations cache */ 724 /* Cache2 is the various normals at the vertices themselves */ 725 /* Cache3 is the various normals for the faces */ 726 needCache2 = needCache3 = GL_FALSE; 727 728 if (qobj->normals == GLU_SMOOTH) { 729 needCache2 = GL_TRUE; 730 } 731 732 if (qobj->normals == GLU_FLAT) { 733 if (qobj->drawStyle != GLU_POINT) { 734 needCache3 = GL_TRUE; 735 } 736 if (qobj->drawStyle == GLU_LINE) { 737 needCache2 = GL_TRUE; 738 } 739 } 740 741 for (i = 0; i < slices; i++) { 742 angle = 2 * PI * i / slices; 743 sinCache1a[i] = SIN(angle); 744 cosCache1a[i] = COS(angle); 745 if (needCache2) { 746 sinCache2a[i] = sinCache1a[i]; 747 cosCache2a[i] = cosCache1a[i]; 748 } 749 } 750 751 for (j = 0; j <= stacks; j++) { 752 angle = PI * j / stacks; 753 if (needCache2) { 754 if (qobj->orientation == GLU_OUTSIDE) { 755 sinCache2b[j] = SIN(angle); 756 cosCache2b[j] = COS(angle); 757 } else { 758 sinCache2b[j] = -SIN(angle); 759 cosCache2b[j] = -COS(angle); 760 } 761 } 762 sinCache1b[j] = radius * SIN(angle); 763 cosCache1b[j] = radius * COS(angle); 764 } 765 /* Make sure it comes to a point */ 766 sinCache1b[0] = 0; 767 sinCache1b[stacks] = 0; 768 769 if (needCache3) { 770 for (i = 0; i < slices; i++) { 771 angle = 2 * PI * (i-0.5) / slices; 772 sinCache3a[i] = SIN(angle); 773 cosCache3a[i] = COS(angle); 774 } 775 for (j = 0; j <= stacks; j++) { 776 angle = PI * (j - 0.5) / stacks; 777 if (qobj->orientation == GLU_OUTSIDE) { 778 sinCache3b[j] = SIN(angle); 779 cosCache3b[j] = COS(angle); 780 } else { 781 sinCache3b[j] = -SIN(angle); 782 cosCache3b[j] = -COS(angle); 783 } 784 } 785 } 786 787 sinCache1a[slices] = sinCache1a[0]; 788 cosCache1a[slices] = cosCache1a[0]; 789 if (needCache2) { 790 sinCache2a[slices] = sinCache2a[0]; 791 cosCache2a[slices] = cosCache2a[0]; 792 } 793 if (needCache3) { 794 sinCache3a[slices] = sinCache3a[0]; 795 cosCache3a[slices] = cosCache3a[0]; 796 } 797 798 switch (qobj->drawStyle) { 799 case GLU_FILL: 800 /* Do ends of sphere as TRIANGLE_FAN's (if not texturing) 801 ** We don't do it when texturing because we need to respecify the 802 ** texture coordinates of the apex for every adjacent vertex (because 803 ** it isn't a constant for that point) 804 */ 805 if (!(qobj->textureCoords)) { 806 start = 1; 807 finish = stacks - 1; 808 809 /* Low end first (j == 0 iteration) */ 810 sintemp2 = sinCache1b[1]; 811 zHigh = cosCache1b[1]; 812 switch(qobj->normals) { 813 case GLU_FLAT: 814 sintemp3 = sinCache3b[1]; 815 costemp3 = cosCache3b[1]; 816 break; 817 case GLU_SMOOTH: 818 sintemp3 = sinCache2b[1]; 819 costemp3 = cosCache2b[1]; 820 glNormal3f(sinCache2a[0] * sinCache2b[0], 821 cosCache2a[0] * sinCache2b[0], 822 cosCache2b[0]); 823 break; 824 default: 825 break; 826 } 827 glBegin(GL_TRIANGLE_FAN); 828 glVertex3f(0.0, 0.0, radius); 829 if (qobj->orientation == GLU_OUTSIDE) { 830 for (i = slices; i >= 0; i--) { 831 switch(qobj->normals) { 832 case GLU_SMOOTH: 833 glNormal3f(sinCache2a[i] * sintemp3, 834 cosCache2a[i] * sintemp3, 835 costemp3); 836 break; 837 case GLU_FLAT: 838 if (i != slices) { 839 glNormal3f(sinCache3a[i+1] * sintemp3, 840 cosCache3a[i+1] * sintemp3, 841 costemp3); 842 } 843 break; 844 case GLU_NONE: 845 default: 846 break; 847 } 848 glVertex3f(sintemp2 * sinCache1a[i], 849 sintemp2 * cosCache1a[i], zHigh); 850 } 851 } else { 852 for (i = 0; i <= slices; i++) { 853 switch(qobj->normals) { 854 case GLU_SMOOTH: 855 glNormal3f(sinCache2a[i] * sintemp3, 856 cosCache2a[i] * sintemp3, 857 costemp3); 858 break; 859 case GLU_FLAT: 860 glNormal3f(sinCache3a[i] * sintemp3, 861 cosCache3a[i] * sintemp3, 862 costemp3); 863 break; 864 case GLU_NONE: 865 default: 866 break; 867 } 868 glVertex3f(sintemp2 * sinCache1a[i], 869 sintemp2 * cosCache1a[i], zHigh); 870 } 871 } 872 glEnd(); 873 874 /* High end next (j == stacks-1 iteration) */ 875 sintemp2 = sinCache1b[stacks-1]; 876 zHigh = cosCache1b[stacks-1]; 877 switch(qobj->normals) { 878 case GLU_FLAT: 879 sintemp3 = sinCache3b[stacks]; 880 costemp3 = cosCache3b[stacks]; 881 break; 882 case GLU_SMOOTH: 883 sintemp3 = sinCache2b[stacks-1]; 884 costemp3 = cosCache2b[stacks-1]; 885 glNormal3f(sinCache2a[stacks] * sinCache2b[stacks], 886 cosCache2a[stacks] * sinCache2b[stacks], 887 cosCache2b[stacks]); 888 break; 889 default: 890 break; 891 } 892 glBegin(GL_TRIANGLE_FAN); 893 glVertex3f(0.0, 0.0, -radius); 894 if (qobj->orientation == GLU_OUTSIDE) { 895 for (i = 0; i <= slices; i++) { 896 switch(qobj->normals) { 897 case GLU_SMOOTH: 898 glNormal3f(sinCache2a[i] * sintemp3, 899 cosCache2a[i] * sintemp3, 900 costemp3); 901 break; 902 case GLU_FLAT: 903 glNormal3f(sinCache3a[i] * sintemp3, 904 cosCache3a[i] * sintemp3, 905 costemp3); 906 break; 907 case GLU_NONE: 908 default: 909 break; 910 } 911 glVertex3f(sintemp2 * sinCache1a[i], 912 sintemp2 * cosCache1a[i], zHigh); 913 } 914 } else { 915 for (i = slices; i >= 0; i--) { 916 switch(qobj->normals) { 917 case GLU_SMOOTH: 918 glNormal3f(sinCache2a[i] * sintemp3, 919 cosCache2a[i] * sintemp3, 920 costemp3); 921 break; 922 case GLU_FLAT: 923 if (i != slices) { 924 glNormal3f(sinCache3a[i+1] * sintemp3, 925 cosCache3a[i+1] * sintemp3, 926 costemp3); 927 } 928 break; 929 case GLU_NONE: 930 default: 931 break; 932 } 933 glVertex3f(sintemp2 * sinCache1a[i], 934 sintemp2 * cosCache1a[i], zHigh); 935 } 936 } 937 glEnd(); 938 } else { 939 start = 0; 940 finish = stacks; 941 } 942 for (j = start; j < finish; j++) { 943 zLow = cosCache1b[j]; 944 zHigh = cosCache1b[j+1]; 945 sintemp1 = sinCache1b[j]; 946 sintemp2 = sinCache1b[j+1]; 947 switch(qobj->normals) { 948 case GLU_FLAT: 949 sintemp4 = sinCache3b[j+1]; 950 costemp4 = cosCache3b[j+1]; 951 break; 952 case GLU_SMOOTH: 953 if (qobj->orientation == GLU_OUTSIDE) { 954 sintemp3 = sinCache2b[j+1]; 955 costemp3 = cosCache2b[j+1]; 956 sintemp4 = sinCache2b[j]; 957 costemp4 = cosCache2b[j]; 958 } else { 959 sintemp3 = sinCache2b[j]; 960 costemp3 = cosCache2b[j]; 961 sintemp4 = sinCache2b[j+1]; 962 costemp4 = cosCache2b[j+1]; 963 } 964 break; 965 default: 966 break; 967 } 968 969 glBegin(GL_QUAD_STRIP); 970 for (i = 0; i <= slices; i++) { 971 switch(qobj->normals) { 972 case GLU_SMOOTH: 973 glNormal3f(sinCache2a[i] * sintemp3, 974 cosCache2a[i] * sintemp3, 975 costemp3); 976 break; 977 case GLU_FLAT: 978 case GLU_NONE: 979 default: 980 break; 981 } 982 if (qobj->orientation == GLU_OUTSIDE) { 983 if (qobj->textureCoords) { 984 glTexCoord2f(1 - (float) i / slices, 985 1 - (float) (j+1) / stacks); 986 } 987 glVertex3f(sintemp2 * sinCache1a[i], 988 sintemp2 * cosCache1a[i], zHigh); 989 } else { 990 if (qobj->textureCoords) { 991 glTexCoord2f(1 - (float) i / slices, 992 1 - (float) j / stacks); 993 } 994 glVertex3f(sintemp1 * sinCache1a[i], 995 sintemp1 * cosCache1a[i], zLow); 996 } 997 switch(qobj->normals) { 998 case GLU_SMOOTH: 999 glNormal3f(sinCache2a[i] * sintemp4, 1000 cosCache2a[i] * sintemp4, 1001 costemp4); 1002 break; 1003 case GLU_FLAT: 1004 glNormal3f(sinCache3a[i] * sintemp4, 1005 cosCache3a[i] * sintemp4, 1006 costemp4); 1007 break; 1008 case GLU_NONE: 1009 default: 1010 break; 1011 } 1012 if (qobj->orientation == GLU_OUTSIDE) { 1013 if (qobj->textureCoords) { 1014 glTexCoord2f(1 - (float) i / slices, 1015 1 - (float) j / stacks); 1016 } 1017 glVertex3f(sintemp1 * sinCache1a[i], 1018 sintemp1 * cosCache1a[i], zLow); 1019 } else { 1020 if (qobj->textureCoords) { 1021 glTexCoord2f(1 - (float) i / slices, 1022 1 - (float) (j+1) / stacks); 1023 } 1024 glVertex3f(sintemp2 * sinCache1a[i], 1025 sintemp2 * cosCache1a[i], zHigh); 1026 } 1027 } 1028 glEnd(); 1029 } 1030 break; 1031 case GLU_POINT: 1032 glBegin(GL_POINTS); 1033 for (j = 0; j <= stacks; j++) { 1034 sintemp1 = sinCache1b[j]; 1035 costemp1 = cosCache1b[j]; 1036 switch(qobj->normals) { 1037 case GLU_FLAT: 1038 case GLU_SMOOTH: 1039 sintemp2 = sinCache2b[j]; 1040 costemp2 = cosCache2b[j]; 1041 break; 1042 default: 1043 break; 1044 } 1045 for (i = 0; i < slices; i++) { 1046 switch(qobj->normals) { 1047 case GLU_FLAT: 1048 case GLU_SMOOTH: 1049 glNormal3f(sinCache2a[i] * sintemp2, 1050 cosCache2a[i] * sintemp2, 1051 costemp2); 1052 break; 1053 case GLU_NONE: 1054 default: 1055 break; 1056 } 1057 1058 zLow = j * radius / stacks; 1059 1060 if (qobj->textureCoords) { 1061 glTexCoord2f(1 - (float) i / slices, 1062 1 - (float) j / stacks); 1063 } 1064 glVertex3f(sintemp1 * sinCache1a[i], 1065 sintemp1 * cosCache1a[i], costemp1); 1066 } 1067 } 1068 glEnd(); 1069 break; 1070 case GLU_LINE: 1071 case GLU_SILHOUETTE: 1072 for (j = 1; j < stacks; j++) { 1073 sintemp1 = sinCache1b[j]; 1074 costemp1 = cosCache1b[j]; 1075 switch(qobj->normals) { 1076 case GLU_FLAT: 1077 case GLU_SMOOTH: 1078 sintemp2 = sinCache2b[j]; 1079 costemp2 = cosCache2b[j]; 1080 break; 1081 default: 1082 break; 1083 } 1084 1085 glBegin(GL_LINE_STRIP); 1086 for (i = 0; i <= slices; i++) { 1087 switch(qobj->normals) { 1088 case GLU_FLAT: 1089 glNormal3f(sinCache3a[i] * sintemp2, 1090 cosCache3a[i] * sintemp2, 1091 costemp2); 1092 break; 1093 case GLU_SMOOTH: 1094 glNormal3f(sinCache2a[i] * sintemp2, 1095 cosCache2a[i] * sintemp2, 1096 costemp2); 1097 break; 1098 case GLU_NONE: 1099 default: 1100 break; 1101 } 1102 if (qobj->textureCoords) { 1103 glTexCoord2f(1 - (float) i / slices, 1104 1 - (float) j / stacks); 1105 } 1106 glVertex3f(sintemp1 * sinCache1a[i], 1107 sintemp1 * cosCache1a[i], costemp1); 1108 } 1109 glEnd(); 1110 } 1111 for (i = 0; i < slices; i++) { 1112 sintemp1 = sinCache1a[i]; 1113 costemp1 = cosCache1a[i]; 1114 switch(qobj->normals) { 1115 case GLU_FLAT: 1116 case GLU_SMOOTH: 1117 sintemp2 = sinCache2a[i]; 1118 costemp2 = cosCache2a[i]; 1119 break; 1120 default: 1121 break; 1122 } 1123 1124 glBegin(GL_LINE_STRIP); 1125 for (j = 0; j <= stacks; j++) { 1126 switch(qobj->normals) { 1127 case GLU_FLAT: 1128 glNormal3f(sintemp2 * sinCache3b[j], 1129 costemp2 * sinCache3b[j], 1130 cosCache3b[j]); 1131 break; 1132 case GLU_SMOOTH: 1133 glNormal3f(sintemp2 * sinCache2b[j], 1134 costemp2 * sinCache2b[j], 1135 cosCache2b[j]); 1136 break; 1137 case GLU_NONE: 1138 default: 1139 break; 1140 } 1141 1142 if (qobj->textureCoords) { 1143 glTexCoord2f(1 - (float) i / slices, 1144 1 - (float) j / stacks); 1145 } 1146 glVertex3f(sintemp1 * sinCache1b[j], 1147 costemp1 * sinCache1b[j], cosCache1b[j]); 1148 } 1149 glEnd(); 1150 } 1151 break; 1152 default: 1153 break; 1154 } 1155 } 1156