Winding.cpp (35033B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../precompiled.h" 31 32 //=============================================================== 33 // 34 // idWinding 35 // 36 //=============================================================== 37 38 /* 39 ============= 40 idWinding::ReAllocate 41 ============= 42 */ 43 bool idWinding::ReAllocate( int n, bool keep ) { 44 idVec5 *oldP; 45 46 oldP = p; 47 n = (n+3) & ~3; // align up to multiple of four 48 p = new (TAG_IDLIB_WINDING) idVec5[n]; 49 if ( oldP ) { 50 if ( keep ) { 51 memcpy( p, oldP, numPoints * sizeof(p[0]) ); 52 } 53 delete[] oldP; 54 } 55 allocedSize = n; 56 57 return true; 58 } 59 60 /* 61 ============= 62 idWinding::BaseForPlane 63 ============= 64 */ 65 void idWinding::BaseForPlane( const idVec3 &normal, const float dist ) { 66 idVec3 org, vright, vup; 67 68 org = normal * dist; 69 70 normal.NormalVectors( vup, vright ); 71 vup *= MAX_WORLD_SIZE; 72 vright *= MAX_WORLD_SIZE; 73 74 EnsureAlloced( 4 ); 75 numPoints = 4; 76 p[0].ToVec3() = org - vright + vup; 77 p[0].s = p[0].t = 0.0f; 78 p[1].ToVec3() = org + vright + vup; 79 p[1].s = p[1].t = 0.0f; 80 p[2].ToVec3() = org + vright - vup; 81 p[2].s = p[2].t = 0.0f; 82 p[3].ToVec3() = org - vright - vup; 83 p[3].s = p[3].t = 0.0f; 84 } 85 86 /* 87 ============= 88 idWinding::Split 89 ============= 90 */ 91 int idWinding::Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const { 92 float * dists; 93 byte * sides; 94 int counts[3]; 95 float dot; 96 int i, j; 97 const idVec5 * p1, *p2; 98 idVec5 mid; 99 idWinding * f, *b; 100 int maxpts; 101 102 assert( this ); 103 104 dists = (float *) _alloca( (numPoints+4) * sizeof( float ) ); 105 sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) ); 106 107 counts[0] = counts[1] = counts[2] = 0; 108 109 // determine sides for each point 110 for ( i = 0; i < numPoints; i++ ) { 111 dists[i] = dot = plane.Distance( p[i].ToVec3() ); 112 if ( dot > epsilon ) { 113 sides[i] = SIDE_FRONT; 114 } else if ( dot < -epsilon ) { 115 sides[i] = SIDE_BACK; 116 } else { 117 sides[i] = SIDE_ON; 118 } 119 counts[sides[i]]++; 120 } 121 sides[i] = sides[0]; 122 dists[i] = dists[0]; 123 124 *front = *back = NULL; 125 126 // if coplanar, put on the front side if the normals match 127 if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) { 128 idPlane windingPlane; 129 130 GetPlane( windingPlane ); 131 if ( windingPlane.Normal() * plane.Normal() > 0.0f ) { 132 *front = Copy(); 133 return SIDE_FRONT; 134 } else { 135 *back = Copy(); 136 return SIDE_BACK; 137 } 138 } 139 // if nothing at the front of the clipping plane 140 if ( !counts[SIDE_FRONT] ) { 141 *back = Copy(); 142 return SIDE_BACK; 143 } 144 // if nothing at the back of the clipping plane 145 if ( !counts[SIDE_BACK] ) { 146 *front = Copy(); 147 return SIDE_FRONT; 148 } 149 150 maxpts = numPoints+4; // cant use counts[0]+2 because of fp grouping errors 151 152 *front = f = new (TAG_IDLIB_WINDING) idWinding(maxpts); 153 *back = b = new (TAG_IDLIB_WINDING) idWinding(maxpts); 154 155 for (i = 0; i < numPoints; i++) { 156 p1 = &p[i]; 157 158 if ( sides[i] == SIDE_ON ) { 159 f->p[f->numPoints] = *p1; 160 f->numPoints++; 161 b->p[b->numPoints] = *p1; 162 b->numPoints++; 163 continue; 164 } 165 166 if ( sides[i] == SIDE_FRONT ) { 167 f->p[f->numPoints] = *p1; 168 f->numPoints++; 169 } 170 171 if ( sides[i] == SIDE_BACK ) { 172 b->p[b->numPoints] = *p1; 173 b->numPoints++; 174 } 175 176 if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { 177 continue; 178 } 179 180 // generate a split point 181 p2 = &p[(i+1)%numPoints]; 182 183 // always calculate the split going from the same side 184 // or minor epsilon issues can happen 185 if ( sides[i] == SIDE_FRONT ) { 186 dot = dists[i] / ( dists[i] - dists[i+1] ); 187 for ( j = 0; j < 3; j++ ) { 188 // avoid round off error when possible 189 if ( plane.Normal()[j] == 1.0f ) { 190 mid[j] = plane.Dist(); 191 } else if ( plane.Normal()[j] == -1.0f ) { 192 mid[j] = -plane.Dist(); 193 } else { 194 mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] ); 195 } 196 } 197 mid.s = p1->s + dot * ( p2->s - p1->s ); 198 mid.t = p1->t + dot * ( p2->t - p1->t ); 199 } else { 200 dot = dists[i+1] / ( dists[i+1] - dists[i] ); 201 for ( j = 0; j < 3; j++ ) { 202 // avoid round off error when possible 203 if ( plane.Normal()[j] == 1.0f ) { 204 mid[j] = plane.Dist(); 205 } else if ( plane.Normal()[j] == -1.0f ) { 206 mid[j] = -plane.Dist(); 207 } else { 208 mid[j] = (*p2)[j] + dot * ( (*p1)[j] - (*p2)[j] ); 209 } 210 } 211 mid.s = p2->s + dot * ( p1->s - p2->s ); 212 mid.t = p2->t + dot * ( p1->t - p2->t ); 213 } 214 215 f->p[f->numPoints] = mid; 216 f->numPoints++; 217 b->p[b->numPoints] = mid; 218 b->numPoints++; 219 } 220 221 if ( f->numPoints > maxpts || b->numPoints > maxpts ) { 222 idLib::common->FatalError( "idWinding::Split: points exceeded estimate." ); 223 } 224 225 return SIDE_CROSS; 226 } 227 228 /* 229 ============= 230 idWinding::Clip 231 ============= 232 */ 233 idWinding *idWinding::Clip( const idPlane &plane, const float epsilon, const bool keepOn ) { 234 float * dists; 235 byte * sides; 236 idVec5 * newPoints; 237 int newNumPoints; 238 int counts[3]; 239 float dot; 240 int i, j; 241 idVec5 * p1, *p2; 242 idVec5 mid; 243 int maxpts; 244 245 assert( this ); 246 247 dists = (float *) _alloca( (numPoints+4) * sizeof( float ) ); 248 sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) ); 249 250 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; 251 252 // determine sides for each point 253 for ( i = 0; i < numPoints; i++ ) { 254 dists[i] = dot = plane.Distance( p[i].ToVec3() ); 255 if ( dot > epsilon ) { 256 sides[i] = SIDE_FRONT; 257 } else if ( dot < -epsilon ) { 258 sides[i] = SIDE_BACK; 259 } else { 260 sides[i] = SIDE_ON; 261 } 262 counts[sides[i]]++; 263 } 264 sides[i] = sides[0]; 265 dists[i] = dists[0]; 266 267 // if the winding is on the plane and we should keep it 268 if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) { 269 return this; 270 } 271 // if nothing at the front of the clipping plane 272 if ( !counts[SIDE_FRONT] ) { 273 delete this; 274 return NULL; 275 } 276 // if nothing at the back of the clipping plane 277 if ( !counts[SIDE_BACK] ) { 278 return this; 279 } 280 281 maxpts = numPoints + 4; // cant use counts[0]+2 because of fp grouping errors 282 283 newPoints = (idVec5 *) _alloca16( maxpts * sizeof( idVec5 ) ); 284 newNumPoints = 0; 285 286 for ( i = 0; i < numPoints; i++ ) { 287 p1 = &p[i]; 288 289 if ( newNumPoints+1 > maxpts ) { 290 return this; // can't split -- fall back to original 291 } 292 293 if ( sides[i] == SIDE_ON ) { 294 newPoints[newNumPoints] = *p1; 295 newNumPoints++; 296 continue; 297 } 298 299 if ( sides[i] == SIDE_FRONT ) { 300 newPoints[newNumPoints] = *p1; 301 newNumPoints++; 302 } 303 304 if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { 305 continue; 306 } 307 308 if ( newNumPoints+1 > maxpts ) { 309 return this; // can't split -- fall back to original 310 } 311 312 // generate a split point 313 p2 = &p[(i+1)%numPoints]; 314 315 dot = dists[i] / (dists[i] - dists[i+1]); 316 for ( j = 0; j < 3; j++ ) { 317 // avoid round off error when possible 318 if ( plane.Normal()[j] == 1.0f ) { 319 mid[j] = plane.Dist(); 320 } else if ( plane.Normal()[j] == -1.0f ) { 321 mid[j] = -plane.Dist(); 322 } else { 323 mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] ); 324 } 325 } 326 mid.s = p1->s + dot * ( p2->s - p1->s ); 327 mid.t = p1->t + dot * ( p2->t - p1->t ); 328 329 newPoints[newNumPoints] = mid; 330 newNumPoints++; 331 } 332 333 if ( !EnsureAlloced( newNumPoints, false ) ) { 334 return this; 335 } 336 337 numPoints = newNumPoints; 338 memcpy( p, newPoints, newNumPoints * sizeof(idVec5) ); 339 340 return this; 341 } 342 343 /* 344 ============= 345 idWinding::ClipInPlace 346 ============= 347 */ 348 bool idWinding::ClipInPlace( const idPlane &plane, const float epsilon, const bool keepOn ) { 349 float* dists; 350 byte * sides; 351 idVec5 * newPoints; 352 int newNumPoints; 353 int counts[3]; 354 float dot; 355 int i, j; 356 idVec5 * p1, *p2; 357 idVec5 mid; 358 int maxpts; 359 360 assert( this ); 361 362 dists = (float *) _alloca( (numPoints+4) * sizeof( float ) ); 363 sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) ); 364 365 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; 366 367 // determine sides for each point 368 for ( i = 0; i < numPoints; i++ ) { 369 dists[i] = dot = plane.Distance( p[i].ToVec3() ); 370 if ( dot > epsilon ) { 371 sides[i] = SIDE_FRONT; 372 } else if ( dot < -epsilon ) { 373 sides[i] = SIDE_BACK; 374 } else { 375 sides[i] = SIDE_ON; 376 } 377 counts[sides[i]]++; 378 } 379 sides[i] = sides[0]; 380 dists[i] = dists[0]; 381 382 // if the winding is on the plane and we should keep it 383 if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) { 384 return true; 385 } 386 // if nothing at the front of the clipping plane 387 if ( !counts[SIDE_FRONT] ) { 388 numPoints = 0; 389 return false; 390 } 391 // if nothing at the back of the clipping plane 392 if ( !counts[SIDE_BACK] ) { 393 return true; 394 } 395 396 maxpts = numPoints + 4; // cant use counts[0]+2 because of fp grouping errors 397 398 newPoints = (idVec5 *) _alloca16( maxpts * sizeof( idVec5 ) ); 399 newNumPoints = 0; 400 401 for ( i = 0; i < numPoints; i++ ) { 402 p1 = &p[i]; 403 404 if ( newNumPoints+1 > maxpts ) { 405 return true; // can't split -- fall back to original 406 } 407 408 if ( sides[i] == SIDE_ON ) { 409 newPoints[newNumPoints] = *p1; 410 newNumPoints++; 411 continue; 412 } 413 414 if ( sides[i] == SIDE_FRONT ) { 415 newPoints[newNumPoints] = *p1; 416 newNumPoints++; 417 } 418 419 if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { 420 continue; 421 } 422 423 if ( newNumPoints+1 > maxpts ) { 424 return true; // can't split -- fall back to original 425 } 426 427 // generate a split point 428 p2 = &p[(i+1)%numPoints]; 429 430 dot = dists[i] / (dists[i] - dists[i+1]); 431 for ( j = 0; j < 3; j++ ) { 432 // avoid round off error when possible 433 if ( plane.Normal()[j] == 1.0f ) { 434 mid[j] = plane.Dist(); 435 } else if ( plane.Normal()[j] == -1.0f ) { 436 mid[j] = -plane.Dist(); 437 } else { 438 mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] ); 439 } 440 } 441 mid.s = p1->s + dot * ( p2->s - p1->s ); 442 mid.t = p1->t + dot * ( p2->t - p1->t ); 443 444 newPoints[newNumPoints] = mid; 445 newNumPoints++; 446 } 447 448 if ( !EnsureAlloced( newNumPoints, false ) ) { 449 return true; 450 } 451 452 numPoints = newNumPoints; 453 memcpy( p, newPoints, newNumPoints * sizeof(idVec5) ); 454 455 return true; 456 } 457 458 /* 459 ============= 460 idWinding::Copy 461 ============= 462 */ 463 idWinding *idWinding::Copy() const { 464 idWinding *w; 465 466 w = new (TAG_IDLIB_WINDING) idWinding( numPoints ); 467 w->numPoints = numPoints; 468 memcpy( w->p, p, numPoints * sizeof(p[0]) ); 469 return w; 470 } 471 472 /* 473 ============= 474 idWinding::Reverse 475 ============= 476 */ 477 idWinding *idWinding::Reverse() const { 478 idWinding *w; 479 int i; 480 481 w = new (TAG_IDLIB_WINDING) idWinding( numPoints ); 482 w->numPoints = numPoints; 483 for ( i = 0; i < numPoints; i++ ) { 484 w->p[ numPoints - i - 1 ] = p[i]; 485 } 486 return w; 487 } 488 489 /* 490 ============= 491 idWinding::ReverseSelf 492 ============= 493 */ 494 void idWinding::ReverseSelf() { 495 idVec5 v; 496 int i; 497 498 for ( i = 0; i < (numPoints>>1); i++ ) { 499 v = p[i]; 500 p[i] = p[numPoints - i - 1]; 501 p[numPoints - i - 1] = v; 502 } 503 } 504 505 /* 506 ============= 507 idWinding::Check 508 ============= 509 */ 510 bool idWinding::Check( bool print ) const { 511 int i, j; 512 float d, edgedist; 513 idVec3 dir, edgenormal; 514 float area; 515 idPlane plane; 516 517 if ( numPoints < 3 ) { 518 if ( print ) { 519 idLib::common->Printf( "idWinding::Check: only %i points.", numPoints ); 520 } 521 return false; 522 } 523 524 area = GetArea(); 525 if ( area < 1.0f ) { 526 if ( print ) { 527 idLib::common->Printf( "idWinding::Check: tiny area: %f", area ); 528 } 529 return false; 530 } 531 532 GetPlane( plane ); 533 534 for ( i = 0; i < numPoints; i++ ) { 535 const idVec3 &p1 = p[i].ToVec3(); 536 537 // check if the winding is huge 538 for ( j = 0; j < 3; j++ ) { 539 if ( p1[j] >= MAX_WORLD_COORD || p1[j] <= MIN_WORLD_COORD ) { 540 if ( print ) { 541 idLib::common->Printf( "idWinding::Check: point %d outside world %c-axis: %f", i, 'X'+j, p1[j] ); 542 } 543 return false; 544 } 545 } 546 547 j = i + 1 == numPoints ? 0 : i + 1; 548 549 // check if the point is on the face plane 550 d = p1 * plane.Normal() + plane[3]; 551 if ( d < -ON_EPSILON || d > ON_EPSILON ) { 552 if ( print ) { 553 idLib::common->Printf( "idWinding::Check: point %d off plane.", i ); 554 } 555 return false; 556 } 557 558 // check if the edge isn't degenerate 559 const idVec3 &p2 = p[j].ToVec3(); 560 dir = p2 - p1; 561 562 if ( dir.Length() < ON_EPSILON) { 563 if ( print ) { 564 idLib::common->Printf( "idWinding::Check: edge %d is degenerate.", i ); 565 } 566 return false; 567 } 568 569 // check if the winding is convex 570 edgenormal = plane.Normal().Cross( dir ); 571 edgenormal.Normalize(); 572 edgedist = p1 * edgenormal; 573 edgedist += ON_EPSILON; 574 575 // all other points must be on front side 576 for ( j = 0; j < numPoints; j++ ) { 577 if ( j == i ) { 578 continue; 579 } 580 d = p[j].ToVec3() * edgenormal; 581 if ( d > edgedist ) { 582 if ( print ) { 583 idLib::common->Printf( "idWinding::Check: non-convex." ); 584 } 585 return false; 586 } 587 } 588 } 589 return true; 590 } 591 592 /* 593 ============= 594 idWinding::GetArea 595 ============= 596 */ 597 float idWinding::GetArea() const { 598 int i; 599 idVec3 d1, d2, cross; 600 float total; 601 602 total = 0.0f; 603 for ( i = 2; i < numPoints; i++ ) { 604 d1 = p[i-1].ToVec3() - p[0].ToVec3(); 605 d2 = p[i].ToVec3() - p[0].ToVec3(); 606 cross = d1.Cross( d2 ); 607 total += cross.Length(); 608 } 609 return total * 0.5f; 610 } 611 612 /* 613 ============= 614 idWinding::GetRadius 615 ============= 616 */ 617 float idWinding::GetRadius( const idVec3 ¢er ) const { 618 int i; 619 float radius, r; 620 idVec3 dir; 621 622 radius = 0.0f; 623 for ( i = 0; i < numPoints; i++ ) { 624 dir = p[i].ToVec3() - center; 625 r = dir * dir; 626 if ( r > radius ) { 627 radius = r; 628 } 629 } 630 return idMath::Sqrt( radius ); 631 } 632 633 /* 634 ============= 635 idWinding::GetCenter 636 ============= 637 */ 638 idVec3 idWinding::GetCenter() const { 639 int i; 640 idVec3 center; 641 642 center.Zero(); 643 for ( i = 0; i < numPoints; i++ ) { 644 center += p[i].ToVec3(); 645 } 646 center *= ( 1.0f / numPoints ); 647 return center; 648 } 649 650 /* 651 ============= 652 idWinding::GetPlane 653 ============= 654 */ 655 void idWinding::GetPlane( idVec3 &normal, float &dist ) const { 656 idVec3 v1, v2, center; 657 658 if ( numPoints < 3 ) { 659 normal.Zero(); 660 dist = 0.0f; 661 return; 662 } 663 664 center = GetCenter(); 665 v1 = p[0].ToVec3() - center; 666 v2 = p[1].ToVec3() - center; 667 normal = v2.Cross( v1 ); 668 normal.Normalize(); 669 dist = p[0].ToVec3() * normal; 670 } 671 672 /* 673 ============= 674 idWinding::GetPlane 675 ============= 676 */ 677 void idWinding::GetPlane( idPlane &plane ) const { 678 idVec3 v1, v2; 679 idVec3 center; 680 681 if ( numPoints < 3 ) { 682 plane.Zero(); 683 return; 684 } 685 686 center = GetCenter(); 687 v1 = p[0].ToVec3() - center; 688 v2 = p[1].ToVec3() - center; 689 plane.SetNormal( v2.Cross( v1 ) ); 690 plane.Normalize(); 691 plane.FitThroughPoint( p[0].ToVec3() ); 692 } 693 694 /* 695 ============= 696 idWinding::GetBounds 697 ============= 698 */ 699 void idWinding::GetBounds( idBounds &bounds ) const { 700 int i; 701 702 if ( !numPoints ) { 703 bounds.Clear(); 704 return; 705 } 706 707 bounds[0] = bounds[1] = p[0].ToVec3(); 708 for ( i = 1; i < numPoints; i++ ) { 709 if ( p[i].x < bounds[0].x ) { 710 bounds[0].x = p[i].x; 711 } else if ( p[i].x > bounds[1].x ) { 712 bounds[1].x = p[i].x; 713 } 714 if ( p[i].y < bounds[0].y ) { 715 bounds[0].y = p[i].y; 716 } else if ( p[i].y > bounds[1].y ) { 717 bounds[1].y = p[i].y; 718 } 719 if ( p[i].z < bounds[0].z ) { 720 bounds[0].z = p[i].z; 721 } else if ( p[i].z > bounds[1].z ) { 722 bounds[1].z = p[i].z; 723 } 724 } 725 } 726 727 /* 728 ============= 729 idWinding::RemoveEqualPoints 730 ============= 731 */ 732 void idWinding::RemoveEqualPoints( const float epsilon ) { 733 int i, j; 734 735 for ( i = 0; i < numPoints; i++ ) { 736 if ( (p[i].ToVec3() - p[(i+numPoints-1)%numPoints].ToVec3()).LengthSqr() >= Square( epsilon ) ) { 737 continue; 738 } 739 numPoints--; 740 for ( j = i; j < numPoints; j++ ) { 741 p[j] = p[j+1]; 742 } 743 i--; 744 } 745 } 746 747 /* 748 ============= 749 idWinding::RemoveColinearPoints 750 ============= 751 */ 752 void idWinding::RemoveColinearPoints( const idVec3 &normal, const float epsilon ) { 753 int i, j; 754 idVec3 edgeNormal; 755 float dist; 756 757 if ( numPoints <= 3 ) { 758 return; 759 } 760 761 for ( i = 0; i < numPoints; i++ ) { 762 763 // create plane through edge orthogonal to winding plane 764 edgeNormal = (p[i].ToVec3() - p[(i+numPoints-1)%numPoints].ToVec3()).Cross( normal ); 765 edgeNormal.Normalize(); 766 dist = edgeNormal * p[i].ToVec3(); 767 768 if ( idMath::Fabs( edgeNormal * p[(i+1)%numPoints].ToVec3() - dist ) > epsilon ) { 769 continue; 770 } 771 772 numPoints--; 773 for ( j = i; j < numPoints; j++ ) { 774 p[j] = p[j+1]; 775 } 776 i--; 777 } 778 } 779 780 /* 781 ============= 782 idWinding::AddToConvexHull 783 784 Adds the given winding to the convex hull. 785 Assumes the current winding already is a convex hull with three or more points. 786 ============= 787 */ 788 void idWinding::AddToConvexHull( const idWinding *winding, const idVec3 &normal, const float epsilon ) { 789 int i, j, k; 790 idVec3 dir; 791 float d; 792 int maxPts; 793 idVec3 * hullDirs; 794 bool * hullSide; 795 bool outside; 796 int numNewHullPoints; 797 idVec5 * newHullPoints; 798 799 if ( !winding ) { 800 return; 801 } 802 803 maxPts = this->numPoints + winding->numPoints; 804 805 if ( !this->EnsureAlloced( maxPts, true ) ) { 806 return; 807 } 808 809 newHullPoints = (idVec5 *) _alloca( maxPts * sizeof( idVec5 ) ); 810 hullDirs = (idVec3 *) _alloca( maxPts * sizeof( idVec3 ) ); 811 hullSide = (bool *) _alloca( maxPts * sizeof( bool ) ); 812 813 for ( i = 0; i < winding->numPoints; i++ ) { 814 const idVec5 &p1 = winding->p[i]; 815 816 // calculate hull edge vectors 817 for ( j = 0; j < this->numPoints; j++ ) { 818 dir = this->p[ (j + 1) % this->numPoints ].ToVec3() - this->p[ j ].ToVec3(); 819 dir.Normalize(); 820 hullDirs[j] = normal.Cross( dir ); 821 } 822 823 // calculate side for each hull edge 824 outside = false; 825 for ( j = 0; j < this->numPoints; j++ ) { 826 dir = p1.ToVec3() - this->p[j].ToVec3(); 827 d = dir * hullDirs[j]; 828 if ( d >= epsilon ) { 829 outside = true; 830 } 831 if ( d >= -epsilon ) { 832 hullSide[j] = true; 833 } else { 834 hullSide[j] = false; 835 } 836 } 837 838 // if the point is effectively inside, do nothing 839 if ( !outside ) { 840 continue; 841 } 842 843 // find the back side to front side transition 844 for ( j = 0; j < this->numPoints; j++ ) { 845 if ( !hullSide[ j ] && hullSide[ (j + 1) % this->numPoints ] ) { 846 break; 847 } 848 } 849 if ( j >= this->numPoints ) { 850 continue; 851 } 852 853 // insert the point here 854 newHullPoints[0] = p1; 855 numNewHullPoints = 1; 856 857 // copy over all points that aren't double fronts 858 j = (j+1) % this->numPoints; 859 for ( k = 0; k < this->numPoints; k++ ) { 860 if ( hullSide[ (j+k) % this->numPoints ] && hullSide[ (j+k+1) % this->numPoints ] ) { 861 continue; 862 } 863 newHullPoints[numNewHullPoints] = this->p[ (j+k+1) % this->numPoints ]; 864 numNewHullPoints++; 865 } 866 867 this->numPoints = numNewHullPoints; 868 memcpy( this->p, newHullPoints, numNewHullPoints * sizeof(idVec5) ); 869 } 870 } 871 872 /* 873 ============= 874 idWinding::AddToConvexHull 875 876 Add a point to the convex hull. 877 The current winding must be convex but may be degenerate and can have less than three points. 878 ============= 879 */ 880 void idWinding::AddToConvexHull( const idVec3 &point, const idVec3 &normal, const float epsilon ) { 881 int j, k, numHullPoints; 882 idVec3 dir; 883 float d; 884 idVec3 * hullDirs; 885 bool * hullSide; 886 idVec5 * hullPoints; 887 bool outside; 888 889 switch( numPoints ) { 890 case 0: { 891 p[0] = point; 892 numPoints++; 893 return; 894 } 895 case 1: { 896 // don't add the same point second 897 if ( p[0].ToVec3().Compare( point, epsilon ) ) { 898 return; 899 } 900 p[1].ToVec3() = point; 901 numPoints++; 902 return; 903 } 904 case 2: { 905 // don't add a point if it already exists 906 if ( p[0].ToVec3().Compare( point, epsilon ) || p[1].ToVec3().Compare( point, epsilon ) ) { 907 return; 908 } 909 // if only two points make sure we have the right ordering according to the normal 910 dir = point - p[0].ToVec3(); 911 dir = dir.Cross( p[1].ToVec3() - p[0].ToVec3() ); 912 if ( dir[0] == 0.0f && dir[1] == 0.0f && dir[2] == 0.0f ) { 913 // points don't make a plane 914 return; 915 } 916 if ( dir * normal > 0.0f ) { 917 p[2].ToVec3() = point; 918 } 919 else { 920 p[2] = p[1]; 921 p[1].ToVec3() = point; 922 } 923 numPoints++; 924 return; 925 } 926 } 927 928 hullDirs = (idVec3 *) _alloca( numPoints * sizeof( idVec3 ) ); 929 hullSide = (bool *) _alloca( numPoints * sizeof( bool ) ); 930 931 // calculate hull edge vectors 932 for ( j = 0; j < numPoints; j++ ) { 933 dir = p[(j + 1) % numPoints].ToVec3() - p[j].ToVec3(); 934 hullDirs[j] = normal.Cross( dir ); 935 } 936 937 // calculate side for each hull edge 938 outside = false; 939 for ( j = 0; j < numPoints; j++ ) { 940 dir = point - p[j].ToVec3(); 941 d = dir * hullDirs[j]; 942 if ( d >= epsilon ) { 943 outside = true; 944 } 945 if ( d >= -epsilon ) { 946 hullSide[j] = true; 947 } else { 948 hullSide[j] = false; 949 } 950 } 951 952 // if the point is effectively inside, do nothing 953 if ( !outside ) { 954 return; 955 } 956 957 // find the back side to front side transition 958 for ( j = 0; j < numPoints; j++ ) { 959 if ( !hullSide[ j ] && hullSide[ (j + 1) % numPoints ] ) { 960 break; 961 } 962 } 963 if ( j >= numPoints ) { 964 return; 965 } 966 967 hullPoints = (idVec5 *) _alloca( (numPoints+1) * sizeof( idVec5 ) ); 968 969 // insert the point here 970 hullPoints[0] = point; 971 numHullPoints = 1; 972 973 // copy over all points that aren't double fronts 974 j = (j+1) % numPoints; 975 for ( k = 0; k < numPoints; k++ ) { 976 if ( hullSide[ (j+k) % numPoints ] && hullSide[ (j+k+1) % numPoints ] ) { 977 continue; 978 } 979 hullPoints[numHullPoints] = p[ (j+k+1) % numPoints ]; 980 numHullPoints++; 981 } 982 983 if ( !EnsureAlloced( numHullPoints, false ) ) { 984 return; 985 } 986 numPoints = numHullPoints; 987 memcpy( p, hullPoints, numHullPoints * sizeof(idVec5) ); 988 } 989 990 /* 991 ============= 992 idWinding::TryMerge 993 ============= 994 */ 995 #define CONTINUOUS_EPSILON 0.005f 996 997 idWinding *idWinding::TryMerge( const idWinding &w, const idVec3 &planenormal, int keep ) const { 998 idVec3 *p1, *p2, *p3, *p4, *back; 999 idWinding *newf; 1000 const idWinding *f1, *f2; 1001 int i, j, k, l; 1002 idVec3 normal, delta; 1003 float dot; 1004 bool keep1, keep2; 1005 1006 f1 = this; 1007 f2 = &w; 1008 // 1009 // find a idLib::common edge 1010 // 1011 p1 = p2 = NULL; // stop compiler warning 1012 j = 0; 1013 1014 for ( i = 0; i < f1->numPoints; i++ ) { 1015 p1 = &f1->p[i].ToVec3(); 1016 p2 = &f1->p[(i+1) % f1->numPoints].ToVec3(); 1017 for ( j = 0; j < f2->numPoints; j++ ) { 1018 p3 = &f2->p[j].ToVec3(); 1019 p4 = &f2->p[(j+1) % f2->numPoints].ToVec3(); 1020 for (k = 0; k < 3; k++ ) { 1021 if ( idMath::Fabs((*p1)[k] - (*p4)[k]) > 0.1f ) { 1022 break; 1023 } 1024 if ( idMath::Fabs((*p2)[k] - (*p3)[k]) > 0.1f ) { 1025 break; 1026 } 1027 } 1028 if ( k == 3 ) { 1029 break; 1030 } 1031 } 1032 if ( j < f2->numPoints ) { 1033 break; 1034 } 1035 } 1036 1037 if ( i == f1->numPoints ) { 1038 return NULL; // no matching edges 1039 } 1040 1041 // 1042 // check slope of connected lines 1043 // if the slopes are colinear, the point can be removed 1044 // 1045 back = &f1->p[(i+f1->numPoints-1)%f1->numPoints].ToVec3(); 1046 delta = (*p1) - (*back); 1047 normal = planenormal.Cross(delta); 1048 normal.Normalize(); 1049 1050 back = &f2->p[(j+2)%f2->numPoints].ToVec3(); 1051 delta = (*back) - (*p1); 1052 dot = delta * normal; 1053 if ( dot > CONTINUOUS_EPSILON ) { 1054 return NULL; // not a convex polygon 1055 } 1056 1057 keep1 = (bool)(dot < -CONTINUOUS_EPSILON); 1058 1059 back = &f1->p[(i+2)%f1->numPoints].ToVec3(); 1060 delta = (*back) - (*p2); 1061 normal = planenormal.Cross( delta ); 1062 normal.Normalize(); 1063 1064 back = &f2->p[(j+f2->numPoints-1)%f2->numPoints].ToVec3(); 1065 delta = (*back) - (*p2); 1066 dot = delta * normal; 1067 if ( dot > CONTINUOUS_EPSILON ) { 1068 return NULL; // not a convex polygon 1069 } 1070 1071 keep2 = (bool)(dot < -CONTINUOUS_EPSILON); 1072 1073 // 1074 // build the new polygon 1075 // 1076 newf = new (TAG_IDLIB_WINDING) idWinding( f1->numPoints + f2->numPoints ); 1077 1078 // copy first polygon 1079 for ( k = (i+1) % f1->numPoints; k != i; k = (k+1) % f1->numPoints ) { 1080 if ( !keep && k == (i+1) % f1->numPoints && !keep2 ) { 1081 continue; 1082 } 1083 1084 newf->p[newf->numPoints] = f1->p[k]; 1085 newf->numPoints++; 1086 } 1087 1088 // copy second polygon 1089 for ( l = (j+1) % f2->numPoints; l != j; l = (l+1) % f2->numPoints ) { 1090 if ( !keep && l == (j+1) % f2->numPoints && !keep1 ) { 1091 continue; 1092 } 1093 newf->p[newf->numPoints] = f2->p[l]; 1094 newf->numPoints++; 1095 } 1096 1097 return newf; 1098 } 1099 1100 /* 1101 ============= 1102 idWinding::RemovePoint 1103 ============= 1104 */ 1105 void idWinding::RemovePoint( int point ) { 1106 if ( point < 0 || point >= numPoints ) { 1107 idLib::common->FatalError( "idWinding::removePoint: point out of range" ); 1108 } 1109 if ( point < numPoints - 1) { 1110 memmove(&p[point], &p[point+1], (numPoints - point - 1) * sizeof(p[0]) ); 1111 } 1112 numPoints--; 1113 } 1114 1115 /* 1116 ============= 1117 idWinding::InsertPoint 1118 ============= 1119 */ 1120 void idWinding::InsertPoint( const idVec5 &point, int spot ) { 1121 int i; 1122 1123 if ( spot > numPoints ) { 1124 idLib::common->FatalError( "idWinding::insertPoint: spot > numPoints" ); 1125 } 1126 1127 if ( spot < 0 ) { 1128 idLib::common->FatalError( "idWinding::insertPoint: spot < 0" ); 1129 } 1130 1131 EnsureAlloced( numPoints+1, true ); 1132 for ( i = numPoints; i > spot; i-- ) { 1133 p[i] = p[i-1]; 1134 } 1135 p[spot] = point; 1136 numPoints++; 1137 } 1138 1139 /* 1140 ============= 1141 idWinding::InsertPointIfOnEdge 1142 ============= 1143 */ 1144 bool idWinding::InsertPointIfOnEdge( const idVec5 &point, const idPlane &plane, const float epsilon ) { 1145 int i; 1146 float dist, dot; 1147 idVec3 normal; 1148 1149 // point may not be too far from the winding plane 1150 if ( idMath::Fabs( plane.Distance( point.ToVec3() ) ) > epsilon ) { 1151 return false; 1152 } 1153 1154 for ( i = 0; i < numPoints; i++ ) { 1155 1156 // create plane through edge orthogonal to winding plane 1157 normal = (p[(i+1)%numPoints].ToVec3() - p[i].ToVec3()).Cross( plane.Normal() ); 1158 normal.Normalize(); 1159 dist = normal * p[i].ToVec3(); 1160 1161 if ( idMath::Fabs( normal * point.ToVec3() - dist ) > epsilon ) { 1162 continue; 1163 } 1164 1165 normal = plane.Normal().Cross( normal ); 1166 dot = normal * point.ToVec3(); 1167 1168 dist = dot - normal * p[i].ToVec3(); 1169 1170 if ( dist < epsilon ) { 1171 // if the winding already has the point 1172 if ( dist > -epsilon ) { 1173 return false; 1174 } 1175 continue; 1176 } 1177 1178 dist = dot - normal * p[(i+1)%numPoints].ToVec3(); 1179 1180 if ( dist > -epsilon ) { 1181 // if the winding already has the point 1182 if ( dist < epsilon ) { 1183 return false; 1184 } 1185 continue; 1186 } 1187 1188 InsertPoint( point, i+1 ); 1189 return true; 1190 } 1191 return false; 1192 } 1193 1194 /* 1195 ============= 1196 idWinding::IsTiny 1197 ============= 1198 */ 1199 #define EDGE_LENGTH 0.2f 1200 1201 bool idWinding::IsTiny() const { 1202 int i; 1203 float len; 1204 idVec3 delta; 1205 int edges; 1206 1207 edges = 0; 1208 for ( i = 0; i < numPoints; i++ ) { 1209 delta = p[(i+1)%numPoints].ToVec3() - p[i].ToVec3(); 1210 len = delta.Length(); 1211 if ( len > EDGE_LENGTH ) { 1212 if ( ++edges == 3 ) { 1213 return false; 1214 } 1215 } 1216 } 1217 return true; 1218 } 1219 1220 /* 1221 ============= 1222 idWinding::IsHuge 1223 ============= 1224 */ 1225 bool idWinding::IsHuge() const { 1226 int i, j; 1227 1228 for ( i = 0; i < numPoints; i++ ) { 1229 for ( j = 0; j < 3; j++ ) { 1230 if ( p[i][j] <= MIN_WORLD_COORD || p[i][j] >= MAX_WORLD_COORD ) { 1231 return true; 1232 } 1233 } 1234 } 1235 return false; 1236 } 1237 1238 /* 1239 ============= 1240 idWinding::Print 1241 ============= 1242 */ 1243 void idWinding::Print() const { 1244 int i; 1245 1246 for ( i = 0; i < numPoints; i++ ) { 1247 idLib::common->Printf( "(%5.1f, %5.1f, %5.1f)\n", p[i][0], p[i][1], p[i][2] ); 1248 } 1249 } 1250 1251 /* 1252 ============= 1253 idWinding::PlaneDistance 1254 ============= 1255 */ 1256 float idWinding::PlaneDistance( const idPlane &plane ) const { 1257 int i; 1258 float d, min, max; 1259 1260 min = idMath::INFINITY; 1261 max = -min; 1262 for ( i = 0; i < numPoints; i++ ) { 1263 d = plane.Distance( p[i].ToVec3() ); 1264 if ( d < min ) { 1265 min = d; 1266 if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) { 1267 return 0.0f; 1268 } 1269 } 1270 if ( d > max ) { 1271 max = d; 1272 if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) { 1273 return 0.0f; 1274 } 1275 } 1276 } 1277 if ( IEEE_FLT_SIGNBITNOTSET( min ) ) { 1278 return min; 1279 } 1280 if ( IEEE_FLT_SIGNBITSET( max ) ) { 1281 return max; 1282 } 1283 return 0.0f; 1284 } 1285 1286 /* 1287 ============= 1288 idWinding::PlaneSide 1289 ============= 1290 */ 1291 int idWinding::PlaneSide( const idPlane &plane, const float epsilon ) const { 1292 bool front, back; 1293 int i; 1294 float d; 1295 1296 front = false; 1297 back = false; 1298 for ( i = 0; i < numPoints; i++ ) { 1299 d = plane.Distance( p[i].ToVec3() ); 1300 if ( d < -epsilon ) { 1301 if ( front ) { 1302 return SIDE_CROSS; 1303 } 1304 back = true; 1305 continue; 1306 } 1307 else if ( d > epsilon ) { 1308 if ( back ) { 1309 return SIDE_CROSS; 1310 } 1311 front = true; 1312 continue; 1313 } 1314 } 1315 1316 if ( back ) { 1317 return SIDE_BACK; 1318 } 1319 if ( front ) { 1320 return SIDE_FRONT; 1321 } 1322 return SIDE_ON; 1323 } 1324 1325 /* 1326 ============= 1327 idWinding::PlanesConcave 1328 ============= 1329 */ 1330 #define WCONVEX_EPSILON 0.2f 1331 1332 bool idWinding::PlanesConcave( const idWinding &w2, const idVec3 &normal1, const idVec3 &normal2, float dist1, float dist2 ) const { 1333 int i; 1334 1335 // check if one of the points of winding 1 is at the back of the plane of winding 2 1336 for ( i = 0; i < numPoints; i++ ) { 1337 if ( normal2 * p[i].ToVec3() - dist2 > WCONVEX_EPSILON ) { 1338 return true; 1339 } 1340 } 1341 // check if one of the points of winding 2 is at the back of the plane of winding 1 1342 for ( i = 0; i < w2.numPoints; i++ ) { 1343 if ( normal1 * w2.p[i].ToVec3() - dist1 > WCONVEX_EPSILON ) { 1344 return true; 1345 } 1346 } 1347 1348 return false; 1349 } 1350 1351 /* 1352 ============= 1353 idWinding::PointInside 1354 ============= 1355 */ 1356 bool idWinding::PointInside( const idVec3 &normal, const idVec3 &point, const float epsilon ) const { 1357 int i; 1358 idVec3 dir, n, pointvec; 1359 1360 for ( i = 0; i < numPoints; i++ ) { 1361 dir = p[(i+1) % numPoints].ToVec3() - p[i].ToVec3(); 1362 pointvec = point - p[i].ToVec3(); 1363 1364 n = dir.Cross( normal ); 1365 1366 if ( pointvec * n < -epsilon ) { 1367 return false; 1368 } 1369 } 1370 return true; 1371 } 1372 1373 /* 1374 ============= 1375 idWinding::LineIntersection 1376 ============= 1377 */ 1378 bool idWinding::LineIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &end, bool backFaceCull ) const { 1379 float front, back, frac; 1380 idVec3 mid; 1381 1382 front = windingPlane.Distance( start ); 1383 back = windingPlane.Distance( end ); 1384 1385 // if both points at the same side of the plane 1386 if ( front < 0.0f && back < 0.0f ) { 1387 return false; 1388 } 1389 1390 if ( front > 0.0f && back > 0.0f ) { 1391 return false; 1392 } 1393 1394 // if back face culled 1395 if ( backFaceCull && front < 0.0f ) { 1396 return false; 1397 } 1398 1399 // get point of intersection with winding plane 1400 if ( idMath::Fabs(front - back) < 0.0001f ) { 1401 mid = end; 1402 } 1403 else { 1404 frac = front / (front - back); 1405 mid[0] = start[0] + (end[0] - start[0]) * frac; 1406 mid[1] = start[1] + (end[1] - start[1]) * frac; 1407 mid[2] = start[2] + (end[2] - start[2]) * frac; 1408 } 1409 1410 return PointInside( windingPlane.Normal(), mid, 0.0f ); 1411 } 1412 1413 /* 1414 ============= 1415 idWinding::RayIntersection 1416 ============= 1417 */ 1418 bool idWinding::RayIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull ) const { 1419 int i; 1420 bool side, lastside = false; 1421 idPluecker pl1, pl2; 1422 1423 scale = 0.0f; 1424 pl1.FromRay( start, dir ); 1425 for ( i = 0; i < numPoints; i++ ) { 1426 pl2.FromLine( p[i].ToVec3(), p[(i+1)%numPoints].ToVec3() ); 1427 side = pl1.PermutedInnerProduct( pl2 ) > 0.0f; 1428 if ( i && side != lastside ) { 1429 return false; 1430 } 1431 lastside = side; 1432 } 1433 if ( !backFaceCull || lastside ) { 1434 windingPlane.RayIntersection( start, dir, scale ); 1435 return true; 1436 } 1437 return false; 1438 } 1439 1440 /* 1441 ================= 1442 idWinding::TriangleArea 1443 ================= 1444 */ 1445 float idWinding::TriangleArea( const idVec3 &a, const idVec3 &b, const idVec3 &c ) { 1446 idVec3 v1, v2; 1447 idVec3 cross; 1448 1449 v1 = b - a; 1450 v2 = c - a; 1451 cross = v1.Cross( v2 ); 1452 return 0.5f * cross.Length(); 1453 } 1454 1455 1456 //=============================================================== 1457 // 1458 // idFixedWinding 1459 // 1460 //=============================================================== 1461 1462 /* 1463 ============= 1464 idFixedWinding::ReAllocate 1465 ============= 1466 */ 1467 bool idFixedWinding::ReAllocate( int n, bool keep ) { 1468 1469 assert( n <= MAX_POINTS_ON_WINDING ); 1470 1471 if ( n > MAX_POINTS_ON_WINDING ) { 1472 idLib::common->Printf("WARNING: idFixedWinding -> MAX_POINTS_ON_WINDING overflowed\n"); 1473 return false; 1474 } 1475 return true; 1476 } 1477 1478 /* 1479 ============= 1480 idFixedWinding::Split 1481 ============= 1482 */ 1483 int idFixedWinding::Split( idFixedWinding *back, const idPlane &plane, const float epsilon ) { 1484 int counts[3]; 1485 float dists[MAX_POINTS_ON_WINDING+4]; 1486 byte sides[MAX_POINTS_ON_WINDING+4]; 1487 float dot; 1488 int i, j; 1489 idVec5 *p1, *p2; 1490 idVec5 mid; 1491 idFixedWinding out; 1492 1493 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; 1494 1495 // determine sides for each point 1496 for ( i = 0; i < numPoints; i++ ) { 1497 dists[i] = dot = plane.Distance( p[i].ToVec3() ); 1498 if ( dot > epsilon ) { 1499 sides[i] = SIDE_FRONT; 1500 } else if ( dot < -epsilon ) { 1501 sides[i] = SIDE_BACK; 1502 } else { 1503 sides[i] = SIDE_ON; 1504 } 1505 counts[sides[i]]++; 1506 } 1507 1508 if ( !counts[SIDE_BACK] ) { 1509 if ( !counts[SIDE_FRONT] ) { 1510 return SIDE_ON; 1511 } 1512 else { 1513 return SIDE_FRONT; 1514 } 1515 } 1516 1517 if ( !counts[SIDE_FRONT] ) { 1518 return SIDE_BACK; 1519 } 1520 1521 sides[i] = sides[0]; 1522 dists[i] = dists[0]; 1523 1524 out.numPoints = 0; 1525 back->numPoints = 0; 1526 1527 for ( i = 0; i < numPoints; i++ ) { 1528 p1 = &p[i]; 1529 1530 if ( !out.EnsureAlloced( out.numPoints+1, true ) ) { 1531 return SIDE_FRONT; // can't split -- fall back to original 1532 } 1533 if ( !back->EnsureAlloced( back->numPoints+1, true ) ) { 1534 return SIDE_FRONT; // can't split -- fall back to original 1535 } 1536 1537 if ( sides[i] == SIDE_ON ) { 1538 out.p[out.numPoints] = *p1; 1539 out.numPoints++; 1540 back->p[back->numPoints] = *p1; 1541 back->numPoints++; 1542 continue; 1543 } 1544 1545 if ( sides[i] == SIDE_FRONT ) { 1546 out.p[out.numPoints] = *p1; 1547 out.numPoints++; 1548 } 1549 if ( sides[i] == SIDE_BACK ) { 1550 back->p[back->numPoints] = *p1; 1551 back->numPoints++; 1552 } 1553 1554 if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { 1555 continue; 1556 } 1557 1558 if ( !out.EnsureAlloced( out.numPoints+1, true ) ) { 1559 return SIDE_FRONT; // can't split -- fall back to original 1560 } 1561 1562 if ( !back->EnsureAlloced( back->numPoints+1, true ) ) { 1563 return SIDE_FRONT; // can't split -- fall back to original 1564 } 1565 1566 // generate a split point 1567 j = i + 1; 1568 if ( j >= numPoints ) { 1569 p2 = &p[0]; 1570 } 1571 else { 1572 p2 = &p[j]; 1573 } 1574 1575 dot = dists[i] / (dists[i] - dists[i+1]); 1576 for ( j = 0; j < 3; j++ ) { 1577 // avoid round off error when possible 1578 if ( plane.Normal()[j] == 1.0f ) { 1579 mid[j] = plane.Dist(); 1580 } else if ( plane.Normal()[j] == -1.0f ) { 1581 mid[j] = -plane.Dist(); 1582 } else { 1583 mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] ); 1584 } 1585 } 1586 mid.s = p1->s + dot * ( p2->s - p1->s ); 1587 mid.t = p1->t + dot * ( p2->t - p1->t ); 1588 1589 out.p[out.numPoints] = mid; 1590 out.numPoints++; 1591 back->p[back->numPoints] = mid; 1592 back->numPoints++; 1593 } 1594 for ( i = 0; i < out.numPoints; i++ ) { 1595 p[i] = out.p[i]; 1596 } 1597 numPoints = out.numPoints; 1598 1599 return SIDE_CROSS; 1600 }