1/* 2** License Applicability. Except to the extent portions of this file are 3** made subject to an alternative license as permitted in the SGI Free 4** Software License B, Version 1.1 (the "License"), the contents of this 5** file are subject only to the provisions of the License. You may not use 6** this file except in compliance with the License. You may obtain a copy 7** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 8** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: 9** 10** http://oss.sgi.com/projects/FreeB 11** 12** Note that, as provided in the License, the Software is distributed on an 13** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS 14** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND 15** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A 16** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. 17** 18** Original Code. The Original Code is: OpenGL Sample Implementation, 19** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, 20** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. 21** Copyright in any portions created by third parties is as indicated 22** elsewhere herein. All Rights Reserved. 23** 24** Additional Notice Provisions: The application programming interfaces 25** established by SGI in conjunction with the Original Code are The 26** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released 27** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version 28** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X 29** Window System(R) (Version 1.3), released October 19, 1998. This software 30** was created using the OpenGL(R) version 1.2.1 Sample Implementation 31** published by SGI, but has not been independently verified as being 32** compliant with the OpenGL(R) version 1.2.1 Specification. 33*/ 34 35/* 36 * nurbstess.c++ 37 * 38 */ 39 40#include "glimports.h" 41#include "myassert.h" 42#include "mysetjmp.h" 43#include "mystdio.h" 44#include "nurbsconsts.h" 45#include "nurbstess.h" 46#include "bufpool.h" 47#include "quilt.h" 48#include "knotvector.h" 49#include "mapdesc.h" 50#include "maplist.h" 51 52void 53NurbsTessellator::set_domain_distance_u_rate(REAL u_rate) 54{ 55 subdivider.set_domain_distance_u_rate(u_rate); 56} 57 58void 59NurbsTessellator::set_domain_distance_v_rate(REAL v_rate) 60{ 61 subdivider.set_domain_distance_v_rate(v_rate); 62} 63 64void 65NurbsTessellator::set_is_domain_distance_sampling(int flag) 66{ 67 subdivider.set_is_domain_distance_sampling(flag); 68} 69 70void 71NurbsTessellator::resetObjects( void ) 72{ 73 subdivider.clear(); 74} 75 76void 77NurbsTessellator::makeobj( int ) 78{ 79#ifndef NDEBUG 80 _glu_dprintf( "makeobj\n" ); 81#endif 82} 83 84void 85NurbsTessellator::closeobj( void ) 86{ 87#ifndef NDEBUG 88 _glu_dprintf( "closeobj\n" ); 89#endif 90} 91 92void 93NurbsTessellator::bgnrender( void ) 94{ 95#ifndef NDEBUG 96 _glu_dprintf( "bgnrender\n" ); 97#endif 98} 99 100void 101NurbsTessellator::endrender( void ) 102{ 103#ifndef NDEBUG 104 _glu_dprintf( "endrender\n" ); 105#endif 106} 107 108/*----------------------------------------------------------------------------- 109 * do_freebgnsurface - free o_surface structure 110 * 111 * Client: do_freeall(), bgnsurface() 112 *----------------------------------------------------------------------------- 113 */ 114void 115NurbsTessellator::do_freebgnsurface( O_surface *o_surface ) 116{ 117 o_surface->deleteMe( o_surfacePool ); 118} 119 120 121/*----------------------------------------------------------------------------- 122 * do_bgnsurface - begin the display of a surface 123 * 124 * Client: bgnsurface() 125 *----------------------------------------------------------------------------- 126 */ 127void 128NurbsTessellator::do_bgnsurface( O_surface *o_surface ) 129{ 130 if( inSurface ) { 131 do_nurbserror( 27 ); 132 endsurface(); 133 } 134 inSurface = 1; 135 136 if( ! playBack ) bgnrender(); 137 138 isTrimModified = 0; 139 isSurfaceModified = 0; 140 isDataValid = 1; 141 numTrims = 0; 142 currentSurface = o_surface; 143 nextTrim = &( currentSurface->o_trim ); 144 nextNurbssurface = &( currentSurface->o_nurbssurface ); 145} 146 147/*----------------------------------------------------------------------------- 148 * do_bgncurve - begin the display of a curve 149 * 150 * Client: bgncurve() 151 *----------------------------------------------------------------------------- 152 */ 153void 154NurbsTessellator::do_bgncurve( O_curve *o_curve ) 155{ 156 if ( inCurve ) { 157 do_nurbserror( 6 ); 158 endcurve(); 159 } 160 161 inCurve = 1; 162 currentCurve = o_curve; 163 currentCurve->curvetype = ct_none; 164 165 if( inTrim ) { 166 if( *nextCurve != o_curve ) { 167 isCurveModified = 1; 168 *nextCurve = o_curve; 169 } 170 } else { 171 if( ! playBack ) bgnrender(); 172 isDataValid = 1; 173 } 174 nextCurve = &(o_curve->next); 175 nextPwlcurve = &(o_curve->curve.o_pwlcurve); 176 nextNurbscurve = &(o_curve->curve.o_nurbscurve); 177} 178 179/*----------------------------------------------------------------------------- 180 * do_endcurve - 181 * 182 * Client: endcurve() 183 *----------------------------------------------------------------------------- 184 */ 185 186void 187NurbsTessellator::do_endcurve( void ) 188{ 189 if( ! inCurve ) { 190 do_nurbserror( 7 ); 191 return; 192 } 193 inCurve = 0; 194 195 *nextCurve = 0; 196 if (currentCurve->curvetype == ct_nurbscurve) 197 *nextNurbscurve = 0; 198 else 199 *nextPwlcurve = 0; 200 201 if ( ! inTrim ) { 202 if( ! isDataValid ) { 203 do_freecurveall( currentCurve ); 204 return; 205 } 206 207 int errval; 208 errval = ::mysetjmp( jumpbuffer ); 209 if( errval == 0 ) { 210 if( currentCurve->curvetype == ct_nurbscurve ) { 211 subdivider.beginQuilts(); 212 for( O_nurbscurve *n = currentCurve->curve.o_nurbscurve; n != 0; n = n->next ) 213 subdivider.addQuilt( n->bezier_curves ); 214 subdivider.endQuilts(); 215 subdivider.drawCurves(); 216 if( ! playBack ) endrender(); 217 } else { 218 /* XXX */ 219 if( ! playBack ) endrender(); 220 /*do_draw_pwlcurve( currentCurve->curve.o_pwlcurve ) */; 221 do_nurbserror( 9 ); 222 } 223 } else { 224 if( ! playBack ) endrender(); 225 do_nurbserror( errval ); 226 } 227 do_freecurveall( currentCurve ); 228 resetObjects(); 229 } 230} 231 232/*----------------------------------------------------------------------------- 233 * do_endsurface - mark end of surface, display surface, free immediate data 234 * 235 * Client: 236 *----------------------------------------------------------------------------- 237 */ 238void 239NurbsTessellator::do_endsurface( void ) 240{ 241 if( inTrim ) { 242 do_nurbserror( 12 ); 243 endtrim(); 244 } 245 246 if( ! inSurface ) { 247 do_nurbserror( 13 ); 248 return; 249 } 250 inSurface = 0; 251 252 *nextNurbssurface = 0; 253 254 if( ! isDataValid ) { 255 do_freeall( ); 256 return; 257 } 258 259 if( *nextTrim != 0 ) { 260 isTrimModified = 1; 261 *nextTrim = 0; 262 } 263 264 int errval; 265 266 errval = ::mysetjmp( jumpbuffer ); 267 if( errval == 0 ) { 268 if( numTrims > 0 ) { 269 270 subdivider.beginTrims(); 271 for( O_trim *trim = currentSurface->o_trim; trim; trim = trim->next ) { 272 subdivider.beginLoop(); 273 for( O_curve *curve = trim->o_curve; curve; curve = curve->next ) { 274 curve->used = 0; 275 assert( curve->curvetype != ct_none ); 276 if (curve->curvetype == ct_pwlcurve) { 277 O_pwlcurve *c = curve->curve.o_pwlcurve; 278 subdivider.addArc( c->npts, c->pts, curve->nuid ); 279 } else { 280 Quilt *quilt = curve->curve.o_nurbscurve->bezier_curves; 281 Quiltspec *qspec = quilt->qspec; 282 REAL *cpts = quilt->cpts + qspec->offset; 283 REAL *cptsend = cpts + (qspec->width * qspec->order * qspec->stride); 284 for( ; cpts != cptsend; cpts += qspec->order*qspec->stride ) 285 subdivider.addArc( cpts, quilt, curve->nuid ); 286 } 287 } 288 subdivider.endLoop(); 289 } 290 subdivider.endTrims(); 291 } 292 293 subdivider.beginQuilts(); 294 for( O_nurbssurface *n = currentSurface->o_nurbssurface; n; n = n->next ) 295 subdivider.addQuilt( n->bezier_patches ); 296 subdivider.endQuilts(); 297 subdivider.drawSurfaces( currentSurface->nuid ); 298 if( ! playBack ) endrender(); 299 } else { 300 if( ! playBack ) endrender(); 301 do_nurbserror( errval ); 302 } 303 304 do_freeall( ); 305 resetObjects(); 306} 307 308/*----------------------------------------------------------------------------- 309 * do_freeall - free all data allocated in immediate mode 310 * 311 * Client: 312 *----------------------------------------------------------------------------- 313 */ 314void 315NurbsTessellator::do_freeall( void ) 316{ 317 for( O_trim *o_trim = currentSurface->o_trim; o_trim; ) { 318 O_trim *next_o_trim = o_trim->next; 319 for( O_curve *curve = o_trim->o_curve; curve; ) { 320 O_curve *next_o_curve = curve->next; 321 do_freecurveall( curve ); 322 curve = next_o_curve; 323 } 324 if( o_trim->save == 0 ) do_freebgntrim( o_trim ); 325 o_trim = next_o_trim; 326 } 327 328 O_nurbssurface *nurbss, *next_nurbss; 329 for( nurbss= currentSurface->o_nurbssurface; nurbss; nurbss = next_nurbss) { 330 next_nurbss = nurbss->next; 331 if( nurbss->save == 0 ) 332 do_freenurbssurface( nurbss ); 333 else 334 nurbss->used = 0; 335 } 336 337 if( currentSurface->save == 0 ) do_freebgnsurface( currentSurface ); 338} 339 340void 341NurbsTessellator::do_freecurveall( O_curve *curve ) 342{ 343 assert( curve->curvetype != ct_none ); 344 345 if( curve->curvetype == ct_nurbscurve ) { 346 O_nurbscurve *ncurve, *next_ncurve; 347 for( ncurve=curve->curve.o_nurbscurve; ncurve; ncurve=next_ncurve ) { 348 next_ncurve = ncurve->next; 349 if( ncurve->save == 0 ) 350 do_freenurbscurve( ncurve ); 351 else 352 ncurve->used = 0; 353 } 354 } else { 355 O_pwlcurve *pcurve, *next_pcurve; 356 for( pcurve=curve->curve.o_pwlcurve; pcurve; pcurve=next_pcurve ) { 357 next_pcurve = pcurve->next; 358 if( pcurve->save == 0 ) 359 do_freepwlcurve( pcurve ); 360 else 361 pcurve->used = 0; 362 } 363 } 364 if( curve->save == 0 ) 365 do_freebgncurve( curve ); 366} 367 368 369/*----------------------------------------------------------------------------- 370 * do_freebgntrim - free the space allocated for a trim loop 371 * 372 * Client: 373 *----------------------------------------------------------------------------- 374 */ 375void 376NurbsTessellator::do_freebgntrim( O_trim *o_trim ) 377{ 378 o_trim->deleteMe( o_trimPool ); 379} 380 381 382/*----------------------------------------------------------------------------- 383 * do_bgntrim - link in a trim loop to the current trimmed surface description 384 * 385 * Client: bgntrim() 386 *----------------------------------------------------------------------------- 387 */ 388void 389NurbsTessellator::do_bgntrim( O_trim *o_trim ) 390{ 391 392 if( ! inSurface ) { 393 do_nurbserror( 15 ); 394 bgnsurface( 0 ); 395 inSurface = 2; 396 } 397 398 if( inTrim ) { 399 do_nurbserror( 16 ); 400 endtrim(); 401 } 402 inTrim = 1; 403 404 if( *nextTrim != o_trim ) { 405 isTrimModified = 1; 406 *nextTrim = o_trim; 407 } 408 409 currentTrim = o_trim; 410 nextTrim = &(o_trim->next); 411 nextCurve = &(o_trim->o_curve); 412} 413 414 415/*----------------------------------------------------------------------------- 416 * do_endtrim - mark the end of the current trim loop 417 * 418 * Client: endtrim() 419 *----------------------------------------------------------------------------- 420 */ 421void 422NurbsTessellator::do_endtrim( void ) 423{ 424 if( ! inTrim ) { 425 do_nurbserror( 17 ); 426 return; 427 } 428 inTrim = 0; 429 430 if( currentTrim->o_curve == 0 ) { 431 do_nurbserror( 18 ); 432 isDataValid = 0; 433 } 434 435 numTrims++; 436 437 if( *nextCurve != 0 ) { 438 isTrimModified = 1; 439 *nextCurve = 0; 440 } 441} 442 443/*----------------------------------------------------------------------------- 444 * do_freepwlcurve - 445 * 446 * Client: 447 *----------------------------------------------------------------------------- 448 */ 449void 450NurbsTessellator::do_freepwlcurve( O_pwlcurve *o_pwlcurve ) 451{ 452 o_pwlcurve->deleteMe( o_pwlcurvePool ); 453} 454 455void 456NurbsTessellator::do_freebgncurve( O_curve *o_curve ) 457{ 458 o_curve->deleteMe( o_curvePool ); 459} 460 461/*----------------------------------------------------------------------------- 462 * do_pwlcurve - link in pwl trim loop to the current surface description 463 * 464 * Client: pwlcurve() 465 *----------------------------------------------------------------------------- 466 */ 467void 468NurbsTessellator::do_pwlcurve( O_pwlcurve *o_pwlcurve ) 469{ 470 if( ! inTrim ) { 471 do_nurbserror( 19 ); 472 if( o_pwlcurve->save == 0 ) 473 do_freepwlcurve(o_pwlcurve ); 474 return; 475 } 476 477 if( ! inCurve ) { 478 bgncurve( 0 ); 479 inCurve = 2; 480 } 481 482 if( o_pwlcurve->used ) { 483 do_nurbserror( 20 ); 484 isDataValid = 0; 485 return; 486 } else 487 o_pwlcurve->used = 1; 488 489 if( currentCurve->curvetype == ct_none ) { 490 currentCurve->curvetype = ct_pwlcurve; 491 } else if( currentCurve->curvetype != ct_pwlcurve ) { 492 do_nurbserror( 21 ); 493 isDataValid = 0; 494 return; 495 } 496 497 if( *nextPwlcurve != o_pwlcurve ) { 498 isCurveModified = 1; 499 *nextPwlcurve = o_pwlcurve; 500 } 501 nextPwlcurve = &(o_pwlcurve->next); 502 503 if( o_pwlcurve->owner != currentCurve ) { 504 isCurveModified = 1; 505 o_pwlcurve->owner = currentCurve; 506 } 507 508 if( inCurve == 2 ) 509 endcurve(); 510} 511 512 513/*----------------------------------------------------------------------------- 514 * do_freenurbscurve - 515 * 516 * Client: 517 *----------------------------------------------------------------------------- 518 */ 519void 520NurbsTessellator::do_freenurbscurve( O_nurbscurve *o_nurbscurve ) 521{ 522 o_nurbscurve->bezier_curves->deleteMe( quiltPool ); 523 o_nurbscurve->deleteMe( o_nurbscurvePool ); 524} 525 526 527/*----------------------------------------------------------------------------- 528 * do_nurbscurve - 529 * 530 * Client: nurbscurve() 531 *----------------------------------------------------------------------------- 532 */ 533void 534NurbsTessellator::do_nurbscurve( O_nurbscurve *o_nurbscurve ) 535{ 536 if ( ! inCurve ) { 537 bgncurve( 0 ); 538 inCurve = 2; 539 } 540 541 if( o_nurbscurve->used ) { 542 /* error - curve was already called in current surface */ 543 do_nurbserror( 23 ); 544 isDataValid = 0; 545 return; 546 } else 547 o_nurbscurve->used = 1; 548 549 if( currentCurve->curvetype == ct_none ) { 550 currentCurve->curvetype = ct_nurbscurve; 551 } else if( currentCurve->curvetype != ct_nurbscurve ) { 552 do_nurbserror( 24 ); 553 isDataValid = 0; 554 return; 555 } 556 557 if( *nextNurbscurve != o_nurbscurve ) { 558 isCurveModified = 1; 559 *nextNurbscurve = o_nurbscurve; 560 } 561 562 nextNurbscurve = &(o_nurbscurve->next); 563 564 if( o_nurbscurve->owner != currentCurve ) { 565 isCurveModified = 1; 566 o_nurbscurve->owner = currentCurve; 567 } 568 569 if( o_nurbscurve->owner == 0 ) 570 isCurveModified = 1; 571 572 if( inCurve == 2 ) 573 endcurve(); 574} 575 576 577/*----------------------------------------------------------------------------- 578 * do_freenurbssurface - 579 * 580 * Client: 581 *----------------------------------------------------------------------------- 582 */ 583 584void 585NurbsTessellator::do_freenurbssurface( O_nurbssurface *o_nurbssurface ) 586{ 587 o_nurbssurface->bezier_patches->deleteMe( quiltPool ); 588 o_nurbssurface->deleteMe( o_nurbssurfacePool ); 589} 590 591/*----------------------------------------------------------------------------- 592 * do_nurbssurface - 593 * 594 * Client: nurbssurface() 595 *----------------------------------------------------------------------------- 596 */ 597void 598NurbsTessellator::do_nurbssurface( O_nurbssurface *o_nurbssurface ) 599{ 600 if( ! inSurface ) { 601 bgnsurface( 0 ); 602 inSurface = 2; 603 } 604 605 if( o_nurbssurface->used ) { 606 /* error - surface was already called in current block */ 607 do_nurbserror( 25 ); 608 isDataValid = 0; 609 return; 610 } else 611 o_nurbssurface->used = 1; 612 613 if( *nextNurbssurface != o_nurbssurface ) { 614 isSurfaceModified = 1; 615 *nextNurbssurface = o_nurbssurface; 616 } 617 618 if( o_nurbssurface->owner != currentSurface ) { 619 isSurfaceModified = 1; 620 o_nurbssurface->owner = currentSurface; 621 } 622 nextNurbssurface = &(o_nurbssurface->next); 623 624 if( inSurface == 2 ) 625 endsurface(); 626} 627 628 629/*----------------------------------------------------------------------------- 630 * do_freenurbsproperty 631 * 632 *----------------------------------------------------------------------------- 633 */ 634 635void 636NurbsTessellator::do_freenurbsproperty( Property *prop ) 637{ 638 prop->deleteMe( propertyPool ); 639} 640 641 642/*----------------------------------------------------------------------------- 643 * do_setnurbsproperty - 644 * 645 *----------------------------------------------------------------------------- 646 */ 647 648void 649NurbsTessellator::do_setnurbsproperty( Property *prop ) 650{ 651 renderhints.setProperty( prop->tag, prop->value ); 652 if( prop->save == 0 ) 653 do_freenurbsproperty( prop ); 654} 655 656void 657NurbsTessellator::do_setnurbsproperty2( Property *prop ) 658{ 659 Mapdesc *mapdesc = maplist.find( prop->type ); 660 661 mapdesc->setProperty( prop->tag, prop->value ); 662 if( prop->save == 0 ) 663 do_freenurbsproperty( prop ); 664} 665 666void 667NurbsTessellator::errorHandler( int ) 668{ 669} 670 671void 672NurbsTessellator::do_nurbserror( int msg ) 673{ 674 errorHandler( msg ); 675} 676 677int 678NurbsTessellator::do_check_knots( Knotvector *knots, const char *msg ) 679{ 680 int status = knots->validate(); 681 if( status ) { 682 do_nurbserror( status ); 683 if( renderhints.errorchecking != N_NOMSG ) knots->show( msg ); 684 } 685 return status; 686} 687 688 689 690 691 692