cm_patch.c (43759B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 #include "cm_local.h" 24 #include "cm_patch.h" 25 26 /* 27 28 This file does not reference any globals, and has these entry points: 29 30 void CM_ClearLevelPatches( void ); 31 struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, const vec3_t *points ); 32 void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ); 33 qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ); 34 void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) ); 35 36 37 WARNING: this may misbehave with meshes that have rows or columns that only 38 degenerate a few triangles. Completely degenerate rows and columns are handled 39 properly. 40 */ 41 42 /* 43 #define MAX_FACETS 1024 44 #define MAX_PATCH_PLANES 2048 45 46 typedef struct { 47 float plane[4]; 48 int signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision 49 } patchPlane_t; 50 51 typedef struct { 52 int surfacePlane; 53 int numBorders; // 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels 54 int borderPlanes[4+6+16]; 55 int borderInward[4+6+16]; 56 qboolean borderNoAdjust[4+6+16]; 57 } facet_t; 58 59 typedef struct patchCollide_s { 60 vec3_t bounds[2]; 61 int numPlanes; // surface planes plus edge planes 62 patchPlane_t *planes; 63 int numFacets; 64 facet_t *facets; 65 } patchCollide_t; 66 67 68 #define MAX_GRID_SIZE 129 69 70 typedef struct { 71 int width; 72 int height; 73 qboolean wrapWidth; 74 qboolean wrapHeight; 75 vec3_t points[MAX_GRID_SIZE][MAX_GRID_SIZE]; // [width][height] 76 } cGrid_t; 77 78 #define SUBDIVIDE_DISTANCE 16 //4 // never more than this units away from curve 79 #define PLANE_TRI_EPSILON 0.1 80 #define WRAP_POINT_EPSILON 0.1 81 */ 82 83 int c_totalPatchBlocks; 84 int c_totalPatchSurfaces; 85 int c_totalPatchEdges; 86 87 static const patchCollide_t *debugPatchCollide; 88 static const facet_t *debugFacet; 89 static qboolean debugBlock; 90 static vec3_t debugBlockPoints[4]; 91 92 /* 93 ================= 94 CM_ClearLevelPatches 95 ================= 96 */ 97 void CM_ClearLevelPatches( void ) { 98 debugPatchCollide = NULL; 99 debugFacet = NULL; 100 } 101 102 /* 103 ================= 104 CM_SignbitsForNormal 105 ================= 106 */ 107 static int CM_SignbitsForNormal( vec3_t normal ) { 108 int bits, j; 109 110 bits = 0; 111 for (j=0 ; j<3 ; j++) { 112 if ( normal[j] < 0 ) { 113 bits |= 1<<j; 114 } 115 } 116 return bits; 117 } 118 119 /* 120 ===================== 121 CM_PlaneFromPoints 122 123 Returns false if the triangle is degenrate. 124 The normal will point out of the clock for clockwise ordered points 125 ===================== 126 */ 127 static qboolean CM_PlaneFromPoints( vec4_t plane, vec3_t a, vec3_t b, vec3_t c ) { 128 vec3_t d1, d2; 129 130 VectorSubtract( b, a, d1 ); 131 VectorSubtract( c, a, d2 ); 132 CrossProduct( d2, d1, plane ); 133 if ( VectorNormalize( plane ) == 0 ) { 134 return qfalse; 135 } 136 137 plane[3] = DotProduct( a, plane ); 138 return qtrue; 139 } 140 141 142 /* 143 ================================================================================ 144 145 GRID SUBDIVISION 146 147 ================================================================================ 148 */ 149 150 /* 151 ================= 152 CM_NeedsSubdivision 153 154 Returns true if the given quadratic curve is not flat enough for our 155 collision detection purposes 156 ================= 157 */ 158 static qboolean CM_NeedsSubdivision( vec3_t a, vec3_t b, vec3_t c ) { 159 vec3_t cmid; 160 vec3_t lmid; 161 vec3_t delta; 162 float dist; 163 int i; 164 165 // calculate the linear midpoint 166 for ( i = 0 ; i < 3 ; i++ ) { 167 lmid[i] = 0.5*(a[i] + c[i]); 168 } 169 170 // calculate the exact curve midpoint 171 for ( i = 0 ; i < 3 ; i++ ) { 172 cmid[i] = 0.5 * ( 0.5*(a[i] + b[i]) + 0.5*(b[i] + c[i]) ); 173 } 174 175 // see if the curve is far enough away from the linear mid 176 VectorSubtract( cmid, lmid, delta ); 177 dist = VectorLength( delta ); 178 179 return dist >= SUBDIVIDE_DISTANCE; 180 } 181 182 /* 183 =============== 184 CM_Subdivide 185 186 a, b, and c are control points. 187 the subdivided sequence will be: a, out1, out2, out3, c 188 =============== 189 */ 190 static void CM_Subdivide( vec3_t a, vec3_t b, vec3_t c, vec3_t out1, vec3_t out2, vec3_t out3 ) { 191 int i; 192 193 for ( i = 0 ; i < 3 ; i++ ) { 194 out1[i] = 0.5 * (a[i] + b[i]); 195 out3[i] = 0.5 * (b[i] + c[i]); 196 out2[i] = 0.5 * (out1[i] + out3[i]); 197 } 198 } 199 200 /* 201 ================= 202 CM_TransposeGrid 203 204 Swaps the rows and columns in place 205 ================= 206 */ 207 static void CM_TransposeGrid( cGrid_t *grid ) { 208 int i, j, l; 209 vec3_t temp; 210 qboolean tempWrap; 211 212 if ( grid->width > grid->height ) { 213 for ( i = 0 ; i < grid->height ; i++ ) { 214 for ( j = i + 1 ; j < grid->width ; j++ ) { 215 if ( j < grid->height ) { 216 // swap the value 217 VectorCopy( grid->points[i][j], temp ); 218 VectorCopy( grid->points[j][i], grid->points[i][j] ); 219 VectorCopy( temp, grid->points[j][i] ); 220 } else { 221 // just copy 222 VectorCopy( grid->points[j][i], grid->points[i][j] ); 223 } 224 } 225 } 226 } else { 227 for ( i = 0 ; i < grid->width ; i++ ) { 228 for ( j = i + 1 ; j < grid->height ; j++ ) { 229 if ( j < grid->width ) { 230 // swap the value 231 VectorCopy( grid->points[j][i], temp ); 232 VectorCopy( grid->points[i][j], grid->points[j][i] ); 233 VectorCopy( temp, grid->points[i][j] ); 234 } else { 235 // just copy 236 VectorCopy( grid->points[i][j], grid->points[j][i] ); 237 } 238 } 239 } 240 } 241 242 l = grid->width; 243 grid->width = grid->height; 244 grid->height = l; 245 246 tempWrap = grid->wrapWidth; 247 grid->wrapWidth = grid->wrapHeight; 248 grid->wrapHeight = tempWrap; 249 } 250 251 /* 252 =================== 253 CM_SetGridWrapWidth 254 255 If the left and right columns are exactly equal, set grid->wrapWidth qtrue 256 =================== 257 */ 258 static void CM_SetGridWrapWidth( cGrid_t *grid ) { 259 int i, j; 260 float d; 261 262 for ( i = 0 ; i < grid->height ; i++ ) { 263 for ( j = 0 ; j < 3 ; j++ ) { 264 d = grid->points[0][i][j] - grid->points[grid->width-1][i][j]; 265 if ( d < -WRAP_POINT_EPSILON || d > WRAP_POINT_EPSILON ) { 266 break; 267 } 268 } 269 if ( j != 3 ) { 270 break; 271 } 272 } 273 if ( i == grid->height ) { 274 grid->wrapWidth = qtrue; 275 } else { 276 grid->wrapWidth = qfalse; 277 } 278 } 279 280 /* 281 ================= 282 CM_SubdivideGridColumns 283 284 Adds columns as necessary to the grid until 285 all the aproximating points are within SUBDIVIDE_DISTANCE 286 from the true curve 287 ================= 288 */ 289 static void CM_SubdivideGridColumns( cGrid_t *grid ) { 290 int i, j, k; 291 292 for ( i = 0 ; i < grid->width - 2 ; ) { 293 // grid->points[i][x] is an interpolating control point 294 // grid->points[i+1][x] is an aproximating control point 295 // grid->points[i+2][x] is an interpolating control point 296 297 // 298 // first see if we can collapse the aproximating collumn away 299 // 300 for ( j = 0 ; j < grid->height ; j++ ) { 301 if ( CM_NeedsSubdivision( grid->points[i][j], grid->points[i+1][j], grid->points[i+2][j] ) ) { 302 break; 303 } 304 } 305 if ( j == grid->height ) { 306 // all of the points were close enough to the linear midpoints 307 // that we can collapse the entire column away 308 for ( j = 0 ; j < grid->height ; j++ ) { 309 // remove the column 310 for ( k = i + 2 ; k < grid->width ; k++ ) { 311 VectorCopy( grid->points[k][j], grid->points[k-1][j] ); 312 } 313 } 314 315 grid->width--; 316 317 // go to the next curve segment 318 i++; 319 continue; 320 } 321 322 // 323 // we need to subdivide the curve 324 // 325 for ( j = 0 ; j < grid->height ; j++ ) { 326 vec3_t prev, mid, next; 327 328 // save the control points now 329 VectorCopy( grid->points[i][j], prev ); 330 VectorCopy( grid->points[i+1][j], mid ); 331 VectorCopy( grid->points[i+2][j], next ); 332 333 // make room for two additional columns in the grid 334 // columns i+1 will be replaced, column i+2 will become i+4 335 // i+1, i+2, and i+3 will be generated 336 for ( k = grid->width - 1 ; k > i + 1 ; k-- ) { 337 VectorCopy( grid->points[k][j], grid->points[k+2][j] ); 338 } 339 340 // generate the subdivided points 341 CM_Subdivide( prev, mid, next, grid->points[i+1][j], grid->points[i+2][j], grid->points[i+3][j] ); 342 } 343 344 grid->width += 2; 345 346 // the new aproximating point at i+1 may need to be removed 347 // or subdivided farther, so don't advance i 348 } 349 } 350 351 /* 352 ====================== 353 CM_ComparePoints 354 ====================== 355 */ 356 #define POINT_EPSILON 0.1 357 static qboolean CM_ComparePoints( float *a, float *b ) { 358 float d; 359 360 d = a[0] - b[0]; 361 if ( d < -POINT_EPSILON || d > POINT_EPSILON ) { 362 return qfalse; 363 } 364 d = a[1] - b[1]; 365 if ( d < -POINT_EPSILON || d > POINT_EPSILON ) { 366 return qfalse; 367 } 368 d = a[2] - b[2]; 369 if ( d < -POINT_EPSILON || d > POINT_EPSILON ) { 370 return qfalse; 371 } 372 return qtrue; 373 } 374 375 /* 376 ================= 377 CM_RemoveDegenerateColumns 378 379 If there are any identical columns, remove them 380 ================= 381 */ 382 static void CM_RemoveDegenerateColumns( cGrid_t *grid ) { 383 int i, j, k; 384 385 for ( i = 0 ; i < grid->width - 1 ; i++ ) { 386 for ( j = 0 ; j < grid->height ; j++ ) { 387 if ( !CM_ComparePoints( grid->points[i][j], grid->points[i+1][j] ) ) { 388 break; 389 } 390 } 391 392 if ( j != grid->height ) { 393 continue; // not degenerate 394 } 395 396 for ( j = 0 ; j < grid->height ; j++ ) { 397 // remove the column 398 for ( k = i + 2 ; k < grid->width ; k++ ) { 399 VectorCopy( grid->points[k][j], grid->points[k-1][j] ); 400 } 401 } 402 grid->width--; 403 404 // check against the next column 405 i--; 406 } 407 } 408 409 /* 410 ================================================================================ 411 412 PATCH COLLIDE GENERATION 413 414 ================================================================================ 415 */ 416 417 static int numPlanes; 418 static patchPlane_t planes[MAX_PATCH_PLANES]; 419 420 static int numFacets; 421 static facet_t facets[MAX_PATCH_PLANES]; //maybe MAX_FACETS ?? 422 423 #define NORMAL_EPSILON 0.0001 424 #define DIST_EPSILON 0.02 425 426 /* 427 ================== 428 CM_PlaneEqual 429 ================== 430 */ 431 int CM_PlaneEqual(patchPlane_t *p, float plane[4], int *flipped) { 432 float invplane[4]; 433 434 if ( 435 fabs(p->plane[0] - plane[0]) < NORMAL_EPSILON 436 && fabs(p->plane[1] - plane[1]) < NORMAL_EPSILON 437 && fabs(p->plane[2] - plane[2]) < NORMAL_EPSILON 438 && fabs(p->plane[3] - plane[3]) < DIST_EPSILON ) 439 { 440 *flipped = qfalse; 441 return qtrue; 442 } 443 444 VectorNegate(plane, invplane); 445 invplane[3] = -plane[3]; 446 447 if ( 448 fabs(p->plane[0] - invplane[0]) < NORMAL_EPSILON 449 && fabs(p->plane[1] - invplane[1]) < NORMAL_EPSILON 450 && fabs(p->plane[2] - invplane[2]) < NORMAL_EPSILON 451 && fabs(p->plane[3] - invplane[3]) < DIST_EPSILON ) 452 { 453 *flipped = qtrue; 454 return qtrue; 455 } 456 457 return qfalse; 458 } 459 460 /* 461 ================== 462 CM_SnapVector 463 ================== 464 */ 465 void CM_SnapVector(vec3_t normal) { 466 int i; 467 468 for (i=0 ; i<3 ; i++) 469 { 470 if ( fabs(normal[i] - 1) < NORMAL_EPSILON ) 471 { 472 VectorClear (normal); 473 normal[i] = 1; 474 break; 475 } 476 if ( fabs(normal[i] - -1) < NORMAL_EPSILON ) 477 { 478 VectorClear (normal); 479 normal[i] = -1; 480 break; 481 } 482 } 483 } 484 485 /* 486 ================== 487 CM_FindPlane2 488 ================== 489 */ 490 int CM_FindPlane2(float plane[4], int *flipped) { 491 int i; 492 493 // see if the points are close enough to an existing plane 494 for ( i = 0 ; i < numPlanes ; i++ ) { 495 if (CM_PlaneEqual(&planes[i], plane, flipped)) return i; 496 } 497 498 // add a new plane 499 if ( numPlanes == MAX_PATCH_PLANES ) { 500 Com_Error( ERR_DROP, "MAX_PATCH_PLANES" ); 501 } 502 503 Vector4Copy( plane, planes[numPlanes].plane ); 504 planes[numPlanes].signbits = CM_SignbitsForNormal( plane ); 505 506 numPlanes++; 507 508 *flipped = qfalse; 509 510 return numPlanes-1; 511 } 512 513 /* 514 ================== 515 CM_FindPlane 516 ================== 517 */ 518 static int CM_FindPlane( float *p1, float *p2, float *p3 ) { 519 float plane[4]; 520 int i; 521 float d; 522 523 if ( !CM_PlaneFromPoints( plane, p1, p2, p3 ) ) { 524 return -1; 525 } 526 527 // see if the points are close enough to an existing plane 528 for ( i = 0 ; i < numPlanes ; i++ ) { 529 if ( DotProduct( plane, planes[i].plane ) < 0 ) { 530 continue; // allow backwards planes? 531 } 532 533 d = DotProduct( p1, planes[i].plane ) - planes[i].plane[3]; 534 if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) { 535 continue; 536 } 537 538 d = DotProduct( p2, planes[i].plane ) - planes[i].plane[3]; 539 if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) { 540 continue; 541 } 542 543 d = DotProduct( p3, planes[i].plane ) - planes[i].plane[3]; 544 if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) { 545 continue; 546 } 547 548 // found it 549 return i; 550 } 551 552 // add a new plane 553 if ( numPlanes == MAX_PATCH_PLANES ) { 554 Com_Error( ERR_DROP, "MAX_PATCH_PLANES" ); 555 } 556 557 Vector4Copy( plane, planes[numPlanes].plane ); 558 planes[numPlanes].signbits = CM_SignbitsForNormal( plane ); 559 560 numPlanes++; 561 562 return numPlanes-1; 563 } 564 565 /* 566 ================== 567 CM_PointOnPlaneSide 568 ================== 569 */ 570 static int CM_PointOnPlaneSide( float *p, int planeNum ) { 571 float *plane; 572 float d; 573 574 if ( planeNum == -1 ) { 575 return SIDE_ON; 576 } 577 plane = planes[ planeNum ].plane; 578 579 d = DotProduct( p, plane ) - plane[3]; 580 581 if ( d > PLANE_TRI_EPSILON ) { 582 return SIDE_FRONT; 583 } 584 585 if ( d < -PLANE_TRI_EPSILON ) { 586 return SIDE_BACK; 587 } 588 589 return SIDE_ON; 590 } 591 592 /* 593 ================== 594 CM_GridPlane 595 ================== 596 */ 597 static int CM_GridPlane( int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int tri ) { 598 int p; 599 600 p = gridPlanes[i][j][tri]; 601 if ( p != -1 ) { 602 return p; 603 } 604 p = gridPlanes[i][j][!tri]; 605 if ( p != -1 ) { 606 return p; 607 } 608 609 // should never happen 610 Com_Printf( "WARNING: CM_GridPlane unresolvable\n" ); 611 return -1; 612 } 613 614 /* 615 ================== 616 CM_EdgePlaneNum 617 ================== 618 */ 619 static int CM_EdgePlaneNum( cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int k ) { 620 float *p1, *p2; 621 vec3_t up; 622 int p; 623 624 switch ( k ) { 625 case 0: // top border 626 p1 = grid->points[i][j]; 627 p2 = grid->points[i+1][j]; 628 p = CM_GridPlane( gridPlanes, i, j, 0 ); 629 VectorMA( p1, 4, planes[ p ].plane, up ); 630 return CM_FindPlane( p1, p2, up ); 631 632 case 2: // bottom border 633 p1 = grid->points[i][j+1]; 634 p2 = grid->points[i+1][j+1]; 635 p = CM_GridPlane( gridPlanes, i, j, 1 ); 636 VectorMA( p1, 4, planes[ p ].plane, up ); 637 return CM_FindPlane( p2, p1, up ); 638 639 case 3: // left border 640 p1 = grid->points[i][j]; 641 p2 = grid->points[i][j+1]; 642 p = CM_GridPlane( gridPlanes, i, j, 1 ); 643 VectorMA( p1, 4, planes[ p ].plane, up ); 644 return CM_FindPlane( p2, p1, up ); 645 646 case 1: // right border 647 p1 = grid->points[i+1][j]; 648 p2 = grid->points[i+1][j+1]; 649 p = CM_GridPlane( gridPlanes, i, j, 0 ); 650 VectorMA( p1, 4, planes[ p ].plane, up ); 651 return CM_FindPlane( p1, p2, up ); 652 653 case 4: // diagonal out of triangle 0 654 p1 = grid->points[i+1][j+1]; 655 p2 = grid->points[i][j]; 656 p = CM_GridPlane( gridPlanes, i, j, 0 ); 657 VectorMA( p1, 4, planes[ p ].plane, up ); 658 return CM_FindPlane( p1, p2, up ); 659 660 case 5: // diagonal out of triangle 1 661 p1 = grid->points[i][j]; 662 p2 = grid->points[i+1][j+1]; 663 p = CM_GridPlane( gridPlanes, i, j, 1 ); 664 VectorMA( p1, 4, planes[ p ].plane, up ); 665 return CM_FindPlane( p1, p2, up ); 666 667 } 668 669 Com_Error( ERR_DROP, "CM_EdgePlaneNum: bad k" ); 670 return -1; 671 } 672 673 /* 674 =================== 675 CM_SetBorderInward 676 =================== 677 */ 678 static void CM_SetBorderInward( facet_t *facet, cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], 679 int i, int j, int which ) { 680 int k, l; 681 float *points[4]; 682 int numPoints; 683 684 switch ( which ) { 685 case -1: 686 points[0] = grid->points[i][j]; 687 points[1] = grid->points[i+1][j]; 688 points[2] = grid->points[i+1][j+1]; 689 points[3] = grid->points[i][j+1]; 690 numPoints = 4; 691 break; 692 case 0: 693 points[0] = grid->points[i][j]; 694 points[1] = grid->points[i+1][j]; 695 points[2] = grid->points[i+1][j+1]; 696 numPoints = 3; 697 break; 698 case 1: 699 points[0] = grid->points[i+1][j+1]; 700 points[1] = grid->points[i][j+1]; 701 points[2] = grid->points[i][j]; 702 numPoints = 3; 703 break; 704 default: 705 Com_Error( ERR_FATAL, "CM_SetBorderInward: bad parameter" ); 706 numPoints = 0; 707 break; 708 } 709 710 for ( k = 0 ; k < facet->numBorders ; k++ ) { 711 int front, back; 712 713 front = 0; 714 back = 0; 715 716 for ( l = 0 ; l < numPoints ; l++ ) { 717 int side; 718 719 side = CM_PointOnPlaneSide( points[l], facet->borderPlanes[k] ); 720 if ( side == SIDE_FRONT ) { 721 front++; 722 } if ( side == SIDE_BACK ) { 723 back++; 724 } 725 } 726 727 if ( front && !back ) { 728 facet->borderInward[k] = qtrue; 729 } else if ( back && !front ) { 730 facet->borderInward[k] = qfalse; 731 } else if ( !front && !back ) { 732 // flat side border 733 facet->borderPlanes[k] = -1; 734 } else { 735 // bisecting side border 736 Com_DPrintf( "WARNING: CM_SetBorderInward: mixed plane sides\n" ); 737 facet->borderInward[k] = qfalse; 738 if ( !debugBlock ) { 739 debugBlock = qtrue; 740 VectorCopy( grid->points[i][j], debugBlockPoints[0] ); 741 VectorCopy( grid->points[i+1][j], debugBlockPoints[1] ); 742 VectorCopy( grid->points[i+1][j+1], debugBlockPoints[2] ); 743 VectorCopy( grid->points[i][j+1], debugBlockPoints[3] ); 744 } 745 } 746 } 747 } 748 749 /* 750 ================== 751 CM_ValidateFacet 752 753 If the facet isn't bounded by its borders, we screwed up. 754 ================== 755 */ 756 static qboolean CM_ValidateFacet( facet_t *facet ) { 757 float plane[4]; 758 int j; 759 winding_t *w; 760 vec3_t bounds[2]; 761 762 if ( facet->surfacePlane == -1 ) { 763 return qfalse; 764 } 765 766 Vector4Copy( planes[ facet->surfacePlane ].plane, plane ); 767 w = BaseWindingForPlane( plane, plane[3] ); 768 for ( j = 0 ; j < facet->numBorders && w ; j++ ) { 769 if ( facet->borderPlanes[j] == -1 ) { 770 return qfalse; 771 } 772 Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane ); 773 if ( !facet->borderInward[j] ) { 774 VectorSubtract( vec3_origin, plane, plane ); 775 plane[3] = -plane[3]; 776 } 777 ChopWindingInPlace( &w, plane, plane[3], 0.1f ); 778 } 779 780 if ( !w ) { 781 return qfalse; // winding was completely chopped away 782 } 783 784 // see if the facet is unreasonably large 785 WindingBounds( w, bounds[0], bounds[1] ); 786 FreeWinding( w ); 787 788 for ( j = 0 ; j < 3 ; j++ ) { 789 if ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) { 790 return qfalse; // we must be missing a plane 791 } 792 if ( bounds[0][j] >= MAX_MAP_BOUNDS ) { 793 return qfalse; 794 } 795 if ( bounds[1][j] <= -MAX_MAP_BOUNDS ) { 796 return qfalse; 797 } 798 } 799 return qtrue; // winding is fine 800 } 801 802 /* 803 ================== 804 CM_AddFacetBevels 805 ================== 806 */ 807 void CM_AddFacetBevels( facet_t *facet ) { 808 809 int i, j, k, l; 810 int axis, dir, order, flipped; 811 float plane[4], d, newplane[4]; 812 winding_t *w, *w2; 813 vec3_t mins, maxs, vec, vec2; 814 815 Vector4Copy( planes[ facet->surfacePlane ].plane, plane ); 816 817 w = BaseWindingForPlane( plane, plane[3] ); 818 for ( j = 0 ; j < facet->numBorders && w ; j++ ) { 819 if (facet->borderPlanes[j] == facet->surfacePlane) continue; 820 Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane ); 821 822 if ( !facet->borderInward[j] ) { 823 VectorSubtract( vec3_origin, plane, plane ); 824 plane[3] = -plane[3]; 825 } 826 827 ChopWindingInPlace( &w, plane, plane[3], 0.1f ); 828 } 829 if ( !w ) { 830 return; 831 } 832 833 WindingBounds(w, mins, maxs); 834 835 // add the axial planes 836 order = 0; 837 for ( axis = 0 ; axis < 3 ; axis++ ) 838 { 839 for ( dir = -1 ; dir <= 1 ; dir += 2, order++ ) 840 { 841 VectorClear(plane); 842 plane[axis] = dir; 843 if (dir == 1) { 844 plane[3] = maxs[axis]; 845 } 846 else { 847 plane[3] = -mins[axis]; 848 } 849 //if it's the surface plane 850 if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { 851 continue; 852 } 853 // see if the plane is allready present 854 for ( i = 0 ; i < facet->numBorders ; i++ ) { 855 if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) 856 break; 857 } 858 859 if ( i == facet->numBorders ) { 860 if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n"); 861 facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped); 862 facet->borderNoAdjust[facet->numBorders] = 0; 863 facet->borderInward[facet->numBorders] = flipped; 864 facet->numBorders++; 865 } 866 } 867 } 868 // 869 // add the edge bevels 870 // 871 // test the non-axial plane edges 872 for ( j = 0 ; j < w->numpoints ; j++ ) 873 { 874 k = (j+1)%w->numpoints; 875 VectorSubtract (w->p[j], w->p[k], vec); 876 //if it's a degenerate edge 877 if (VectorNormalize (vec) < 0.5) 878 continue; 879 CM_SnapVector(vec); 880 for ( k = 0; k < 3 ; k++ ) 881 if ( vec[k] == -1 || vec[k] == 1 ) 882 break; // axial 883 if ( k < 3 ) 884 continue; // only test non-axial edges 885 886 // try the six possible slanted axials from this edge 887 for ( axis = 0 ; axis < 3 ; axis++ ) 888 { 889 for ( dir = -1 ; dir <= 1 ; dir += 2 ) 890 { 891 // construct a plane 892 VectorClear (vec2); 893 vec2[axis] = dir; 894 CrossProduct (vec, vec2, plane); 895 if (VectorNormalize (plane) < 0.5) 896 continue; 897 plane[3] = DotProduct (w->p[j], plane); 898 899 // if all the points of the facet winding are 900 // behind this plane, it is a proper edge bevel 901 for ( l = 0 ; l < w->numpoints ; l++ ) 902 { 903 d = DotProduct (w->p[l], plane) - plane[3]; 904 if (d > 0.1) 905 break; // point in front 906 } 907 if ( l < w->numpoints ) 908 continue; 909 910 //if it's the surface plane 911 if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { 912 continue; 913 } 914 // see if the plane is allready present 915 for ( i = 0 ; i < facet->numBorders ; i++ ) { 916 if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) { 917 break; 918 } 919 } 920 921 if ( i == facet->numBorders ) { 922 if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n"); 923 facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped); 924 925 for ( k = 0 ; k < facet->numBorders ; k++ ) { 926 if (facet->borderPlanes[facet->numBorders] == 927 facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n"); 928 } 929 930 facet->borderNoAdjust[facet->numBorders] = 0; 931 facet->borderInward[facet->numBorders] = flipped; 932 // 933 w2 = CopyWinding(w); 934 Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane); 935 if (!facet->borderInward[facet->numBorders]) 936 { 937 VectorNegate(newplane, newplane); 938 newplane[3] = -newplane[3]; 939 } //end if 940 ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f ); 941 if (!w2) { 942 Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n"); 943 continue; 944 } 945 else { 946 FreeWinding(w2); 947 } 948 // 949 facet->numBorders++; 950 //already got a bevel 951 // break; 952 } 953 } 954 } 955 } 956 FreeWinding( w ); 957 958 #ifndef BSPC 959 //add opposite plane 960 facet->borderPlanes[facet->numBorders] = facet->surfacePlane; 961 facet->borderNoAdjust[facet->numBorders] = 0; 962 facet->borderInward[facet->numBorders] = qtrue; 963 facet->numBorders++; 964 #endif //BSPC 965 966 } 967 968 typedef enum { 969 EN_TOP, 970 EN_RIGHT, 971 EN_BOTTOM, 972 EN_LEFT 973 } edgeName_t; 974 975 /* 976 ================== 977 CM_PatchCollideFromGrid 978 ================== 979 */ 980 static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { 981 int i, j; 982 float *p1, *p2, *p3; 983 MAC_STATIC int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2]; 984 facet_t *facet; 985 int borders[4]; 986 int noAdjust[4]; 987 988 numPlanes = 0; 989 numFacets = 0; 990 991 // find the planes for each triangle of the grid 992 for ( i = 0 ; i < grid->width - 1 ; i++ ) { 993 for ( j = 0 ; j < grid->height - 1 ; j++ ) { 994 p1 = grid->points[i][j]; 995 p2 = grid->points[i+1][j]; 996 p3 = grid->points[i+1][j+1]; 997 gridPlanes[i][j][0] = CM_FindPlane( p1, p2, p3 ); 998 999 p1 = grid->points[i+1][j+1]; 1000 p2 = grid->points[i][j+1]; 1001 p3 = grid->points[i][j]; 1002 gridPlanes[i][j][1] = CM_FindPlane( p1, p2, p3 ); 1003 } 1004 } 1005 1006 // create the borders for each facet 1007 for ( i = 0 ; i < grid->width - 1 ; i++ ) { 1008 for ( j = 0 ; j < grid->height - 1 ; j++ ) { 1009 1010 borders[EN_TOP] = -1; 1011 if ( j > 0 ) { 1012 borders[EN_TOP] = gridPlanes[i][j-1][1]; 1013 } else if ( grid->wrapHeight ) { 1014 borders[EN_TOP] = gridPlanes[i][grid->height-2][1]; 1015 } 1016 noAdjust[EN_TOP] = ( borders[EN_TOP] == gridPlanes[i][j][0] ); 1017 if ( borders[EN_TOP] == -1 || noAdjust[EN_TOP] ) { 1018 borders[EN_TOP] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 0 ); 1019 } 1020 1021 borders[EN_BOTTOM] = -1; 1022 if ( j < grid->height - 2 ) { 1023 borders[EN_BOTTOM] = gridPlanes[i][j+1][0]; 1024 } else if ( grid->wrapHeight ) { 1025 borders[EN_BOTTOM] = gridPlanes[i][0][0]; 1026 } 1027 noAdjust[EN_BOTTOM] = ( borders[EN_BOTTOM] == gridPlanes[i][j][1] ); 1028 if ( borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM] ) { 1029 borders[EN_BOTTOM] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 2 ); 1030 } 1031 1032 borders[EN_LEFT] = -1; 1033 if ( i > 0 ) { 1034 borders[EN_LEFT] = gridPlanes[i-1][j][0]; 1035 } else if ( grid->wrapWidth ) { 1036 borders[EN_LEFT] = gridPlanes[grid->width-2][j][0]; 1037 } 1038 noAdjust[EN_LEFT] = ( borders[EN_LEFT] == gridPlanes[i][j][1] ); 1039 if ( borders[EN_LEFT] == -1 || noAdjust[EN_LEFT] ) { 1040 borders[EN_LEFT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 3 ); 1041 } 1042 1043 borders[EN_RIGHT] = -1; 1044 if ( i < grid->width - 2 ) { 1045 borders[EN_RIGHT] = gridPlanes[i+1][j][1]; 1046 } else if ( grid->wrapWidth ) { 1047 borders[EN_RIGHT] = gridPlanes[0][j][1]; 1048 } 1049 noAdjust[EN_RIGHT] = ( borders[EN_RIGHT] == gridPlanes[i][j][0] ); 1050 if ( borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT] ) { 1051 borders[EN_RIGHT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 1 ); 1052 } 1053 1054 if ( numFacets == MAX_FACETS ) { 1055 Com_Error( ERR_DROP, "MAX_FACETS" ); 1056 } 1057 facet = &facets[numFacets]; 1058 Com_Memset( facet, 0, sizeof( *facet ) ); 1059 1060 if ( gridPlanes[i][j][0] == gridPlanes[i][j][1] ) { 1061 if ( gridPlanes[i][j][0] == -1 ) { 1062 continue; // degenrate 1063 } 1064 facet->surfacePlane = gridPlanes[i][j][0]; 1065 facet->numBorders = 4; 1066 facet->borderPlanes[0] = borders[EN_TOP]; 1067 facet->borderNoAdjust[0] = noAdjust[EN_TOP]; 1068 facet->borderPlanes[1] = borders[EN_RIGHT]; 1069 facet->borderNoAdjust[1] = noAdjust[EN_RIGHT]; 1070 facet->borderPlanes[2] = borders[EN_BOTTOM]; 1071 facet->borderNoAdjust[2] = noAdjust[EN_BOTTOM]; 1072 facet->borderPlanes[3] = borders[EN_LEFT]; 1073 facet->borderNoAdjust[3] = noAdjust[EN_LEFT]; 1074 CM_SetBorderInward( facet, grid, gridPlanes, i, j, -1 ); 1075 if ( CM_ValidateFacet( facet ) ) { 1076 CM_AddFacetBevels( facet ); 1077 numFacets++; 1078 } 1079 } else { 1080 // two seperate triangles 1081 facet->surfacePlane = gridPlanes[i][j][0]; 1082 facet->numBorders = 3; 1083 facet->borderPlanes[0] = borders[EN_TOP]; 1084 facet->borderNoAdjust[0] = noAdjust[EN_TOP]; 1085 facet->borderPlanes[1] = borders[EN_RIGHT]; 1086 facet->borderNoAdjust[1] = noAdjust[EN_RIGHT]; 1087 facet->borderPlanes[2] = gridPlanes[i][j][1]; 1088 if ( facet->borderPlanes[2] == -1 ) { 1089 facet->borderPlanes[2] = borders[EN_BOTTOM]; 1090 if ( facet->borderPlanes[2] == -1 ) { 1091 facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 4 ); 1092 } 1093 } 1094 CM_SetBorderInward( facet, grid, gridPlanes, i, j, 0 ); 1095 if ( CM_ValidateFacet( facet ) ) { 1096 CM_AddFacetBevels( facet ); 1097 numFacets++; 1098 } 1099 1100 if ( numFacets == MAX_FACETS ) { 1101 Com_Error( ERR_DROP, "MAX_FACETS" ); 1102 } 1103 facet = &facets[numFacets]; 1104 Com_Memset( facet, 0, sizeof( *facet ) ); 1105 1106 facet->surfacePlane = gridPlanes[i][j][1]; 1107 facet->numBorders = 3; 1108 facet->borderPlanes[0] = borders[EN_BOTTOM]; 1109 facet->borderNoAdjust[0] = noAdjust[EN_BOTTOM]; 1110 facet->borderPlanes[1] = borders[EN_LEFT]; 1111 facet->borderNoAdjust[1] = noAdjust[EN_LEFT]; 1112 facet->borderPlanes[2] = gridPlanes[i][j][0]; 1113 if ( facet->borderPlanes[2] == -1 ) { 1114 facet->borderPlanes[2] = borders[EN_TOP]; 1115 if ( facet->borderPlanes[2] == -1 ) { 1116 facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 5 ); 1117 } 1118 } 1119 CM_SetBorderInward( facet, grid, gridPlanes, i, j, 1 ); 1120 if ( CM_ValidateFacet( facet ) ) { 1121 CM_AddFacetBevels( facet ); 1122 numFacets++; 1123 } 1124 } 1125 } 1126 } 1127 1128 // copy the results out 1129 pf->numPlanes = numPlanes; 1130 pf->numFacets = numFacets; 1131 pf->facets = Hunk_Alloc( numFacets * sizeof( *pf->facets ), h_high ); 1132 Com_Memcpy( pf->facets, facets, numFacets * sizeof( *pf->facets ) ); 1133 pf->planes = Hunk_Alloc( numPlanes * sizeof( *pf->planes ), h_high ); 1134 Com_Memcpy( pf->planes, planes, numPlanes * sizeof( *pf->planes ) ); 1135 } 1136 1137 1138 /* 1139 =================== 1140 CM_GeneratePatchCollide 1141 1142 Creates an internal structure that will be used to perform 1143 collision detection with a patch mesh. 1144 1145 Points is packed as concatenated rows. 1146 =================== 1147 */ 1148 struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *points ) { 1149 patchCollide_t *pf; 1150 MAC_STATIC cGrid_t grid; 1151 int i, j; 1152 1153 if ( width <= 2 || height <= 2 || !points ) { 1154 Com_Error( ERR_DROP, "CM_GeneratePatchFacets: bad parameters: (%i, %i, %p)", 1155 width, height, points ); 1156 } 1157 1158 if ( !(width & 1) || !(height & 1) ) { 1159 Com_Error( ERR_DROP, "CM_GeneratePatchFacets: even sizes are invalid for quadratic meshes" ); 1160 } 1161 1162 if ( width > MAX_GRID_SIZE || height > MAX_GRID_SIZE ) { 1163 Com_Error( ERR_DROP, "CM_GeneratePatchFacets: source is > MAX_GRID_SIZE" ); 1164 } 1165 1166 // build a grid 1167 grid.width = width; 1168 grid.height = height; 1169 grid.wrapWidth = qfalse; 1170 grid.wrapHeight = qfalse; 1171 for ( i = 0 ; i < width ; i++ ) { 1172 for ( j = 0 ; j < height ; j++ ) { 1173 VectorCopy( points[j*width + i], grid.points[i][j] ); 1174 } 1175 } 1176 1177 // subdivide the grid 1178 CM_SetGridWrapWidth( &grid ); 1179 CM_SubdivideGridColumns( &grid ); 1180 CM_RemoveDegenerateColumns( &grid ); 1181 1182 CM_TransposeGrid( &grid ); 1183 1184 CM_SetGridWrapWidth( &grid ); 1185 CM_SubdivideGridColumns( &grid ); 1186 CM_RemoveDegenerateColumns( &grid ); 1187 1188 // we now have a grid of points exactly on the curve 1189 // the aproximate surface defined by these points will be 1190 // collided against 1191 pf = Hunk_Alloc( sizeof( *pf ), h_high ); 1192 ClearBounds( pf->bounds[0], pf->bounds[1] ); 1193 for ( i = 0 ; i < grid.width ; i++ ) { 1194 for ( j = 0 ; j < grid.height ; j++ ) { 1195 AddPointToBounds( grid.points[i][j], pf->bounds[0], pf->bounds[1] ); 1196 } 1197 } 1198 1199 c_totalPatchBlocks += ( grid.width - 1 ) * ( grid.height - 1 ); 1200 1201 // generate a bsp tree for the surface 1202 CM_PatchCollideFromGrid( &grid, pf ); 1203 1204 // expand by one unit for epsilon purposes 1205 pf->bounds[0][0] -= 1; 1206 pf->bounds[0][1] -= 1; 1207 pf->bounds[0][2] -= 1; 1208 1209 pf->bounds[1][0] += 1; 1210 pf->bounds[1][1] += 1; 1211 pf->bounds[1][2] += 1; 1212 1213 return pf; 1214 } 1215 1216 /* 1217 ================================================================================ 1218 1219 TRACE TESTING 1220 1221 ================================================================================ 1222 */ 1223 1224 /* 1225 ==================== 1226 CM_TracePointThroughPatchCollide 1227 1228 special case for point traces because the patch collide "brushes" have no volume 1229 ==================== 1230 */ 1231 void CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) { 1232 qboolean frontFacing[MAX_PATCH_PLANES]; 1233 float intersection[MAX_PATCH_PLANES]; 1234 float intersect; 1235 const patchPlane_t *planes; 1236 const facet_t *facet; 1237 int i, j, k; 1238 float offset; 1239 float d1, d2; 1240 #ifndef BSPC 1241 static cvar_t *cv; 1242 #endif //BSPC 1243 1244 #ifndef BSPC 1245 if ( !cm_playerCurveClip->integer || !tw->isPoint ) { 1246 return; 1247 } 1248 #endif 1249 1250 // determine the trace's relationship to all planes 1251 planes = pc->planes; 1252 for ( i = 0 ; i < pc->numPlanes ; i++, planes++ ) { 1253 offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane ); 1254 d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset; 1255 d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset; 1256 if ( d1 <= 0 ) { 1257 frontFacing[i] = qfalse; 1258 } else { 1259 frontFacing[i] = qtrue; 1260 } 1261 if ( d1 == d2 ) { 1262 intersection[i] = 99999; 1263 } else { 1264 intersection[i] = d1 / ( d1 - d2 ); 1265 if ( intersection[i] <= 0 ) { 1266 intersection[i] = 99999; 1267 } 1268 } 1269 } 1270 1271 1272 // see if any of the surface planes are intersected 1273 facet = pc->facets; 1274 for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) { 1275 if ( !frontFacing[facet->surfacePlane] ) { 1276 continue; 1277 } 1278 intersect = intersection[facet->surfacePlane]; 1279 if ( intersect < 0 ) { 1280 continue; // surface is behind the starting point 1281 } 1282 if ( intersect > tw->trace.fraction ) { 1283 continue; // already hit something closer 1284 } 1285 for ( j = 0 ; j < facet->numBorders ; j++ ) { 1286 k = facet->borderPlanes[j]; 1287 if ( frontFacing[k] ^ facet->borderInward[j] ) { 1288 if ( intersection[k] > intersect ) { 1289 break; 1290 } 1291 } else { 1292 if ( intersection[k] < intersect ) { 1293 break; 1294 } 1295 } 1296 } 1297 if ( j == facet->numBorders ) { 1298 // we hit this facet 1299 #ifndef BSPC 1300 if (!cv) { 1301 cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 ); 1302 } 1303 if (cv->integer) { 1304 debugPatchCollide = pc; 1305 debugFacet = facet; 1306 } 1307 #endif //BSPC 1308 planes = &pc->planes[facet->surfacePlane]; 1309 1310 // calculate intersection with a slight pushoff 1311 offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane ); 1312 d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset; 1313 d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset; 1314 tw->trace.fraction = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 ); 1315 1316 if ( tw->trace.fraction < 0 ) { 1317 tw->trace.fraction = 0; 1318 } 1319 1320 VectorCopy( planes->plane, tw->trace.plane.normal ); 1321 tw->trace.plane.dist = planes->plane[3]; 1322 } 1323 } 1324 } 1325 1326 /* 1327 ==================== 1328 CM_CheckFacetPlane 1329 ==================== 1330 */ 1331 int CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, float *leaveFrac, int *hit) { 1332 float d1, d2, f; 1333 1334 *hit = qfalse; 1335 1336 d1 = DotProduct( start, plane ) - plane[3]; 1337 d2 = DotProduct( end, plane ) - plane[3]; 1338 1339 // if completely in front of face, no intersection with the entire facet 1340 if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) { 1341 return qfalse; 1342 } 1343 1344 // if it doesn't cross the plane, the plane isn't relevent 1345 if (d1 <= 0 && d2 <= 0 ) { 1346 return qtrue; 1347 } 1348 1349 // crosses face 1350 if (d1 > d2) { // enter 1351 f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2); 1352 if ( f < 0 ) { 1353 f = 0; 1354 } 1355 //always favor previous plane hits and thus also the surface plane hit 1356 if (f > *enterFrac) { 1357 *enterFrac = f; 1358 *hit = qtrue; 1359 } 1360 } else { // leave 1361 f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2); 1362 if ( f > 1 ) { 1363 f = 1; 1364 } 1365 if (f < *leaveFrac) { 1366 *leaveFrac = f; 1367 } 1368 } 1369 return qtrue; 1370 } 1371 1372 /* 1373 ==================== 1374 CM_TraceThroughPatchCollide 1375 ==================== 1376 */ 1377 void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) { 1378 int i, j, hit, hitnum; 1379 float offset, enterFrac, leaveFrac, t; 1380 patchPlane_t *planes; 1381 facet_t *facet; 1382 float plane[4], bestplane[4]; 1383 vec3_t startp, endp; 1384 #ifndef BSPC 1385 static cvar_t *cv; 1386 #endif //BSPC 1387 1388 if (tw->isPoint) { 1389 CM_TracePointThroughPatchCollide( tw, pc ); 1390 return; 1391 } 1392 1393 facet = pc->facets; 1394 for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) { 1395 enterFrac = -1.0; 1396 leaveFrac = 1.0; 1397 hitnum = -1; 1398 // 1399 planes = &pc->planes[ facet->surfacePlane ]; 1400 VectorCopy(planes->plane, plane); 1401 plane[3] = planes->plane[3]; 1402 if ( tw->sphere.use ) { 1403 // adjust the plane distance apropriately for radius 1404 plane[3] += tw->sphere.radius; 1405 1406 // find the closest point on the capsule to the plane 1407 t = DotProduct( plane, tw->sphere.offset ); 1408 if ( t > 0.0f ) { 1409 VectorSubtract( tw->start, tw->sphere.offset, startp ); 1410 VectorSubtract( tw->end, tw->sphere.offset, endp ); 1411 } 1412 else { 1413 VectorAdd( tw->start, tw->sphere.offset, startp ); 1414 VectorAdd( tw->end, tw->sphere.offset, endp ); 1415 } 1416 } 1417 else { 1418 offset = DotProduct( tw->offsets[ planes->signbits ], plane); 1419 plane[3] -= offset; 1420 VectorCopy( tw->start, startp ); 1421 VectorCopy( tw->end, endp ); 1422 } 1423 1424 if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) { 1425 continue; 1426 } 1427 if (hit) { 1428 Vector4Copy(plane, bestplane); 1429 } 1430 1431 for ( j = 0; j < facet->numBorders; j++ ) { 1432 planes = &pc->planes[ facet->borderPlanes[j] ]; 1433 if (facet->borderInward[j]) { 1434 VectorNegate(planes->plane, plane); 1435 plane[3] = -planes->plane[3]; 1436 } 1437 else { 1438 VectorCopy(planes->plane, plane); 1439 plane[3] = planes->plane[3]; 1440 } 1441 if ( tw->sphere.use ) { 1442 // adjust the plane distance apropriately for radius 1443 plane[3] += tw->sphere.radius; 1444 1445 // find the closest point on the capsule to the plane 1446 t = DotProduct( plane, tw->sphere.offset ); 1447 if ( t > 0.0f ) { 1448 VectorSubtract( tw->start, tw->sphere.offset, startp ); 1449 VectorSubtract( tw->end, tw->sphere.offset, endp ); 1450 } 1451 else { 1452 VectorAdd( tw->start, tw->sphere.offset, startp ); 1453 VectorAdd( tw->end, tw->sphere.offset, endp ); 1454 } 1455 } 1456 else { 1457 // NOTE: this works even though the plane might be flipped because the bbox is centered 1458 offset = DotProduct( tw->offsets[ planes->signbits ], plane); 1459 plane[3] += fabs(offset); 1460 VectorCopy( tw->start, startp ); 1461 VectorCopy( tw->end, endp ); 1462 } 1463 1464 if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) { 1465 break; 1466 } 1467 if (hit) { 1468 hitnum = j; 1469 Vector4Copy(plane, bestplane); 1470 } 1471 } 1472 if (j < facet->numBorders) continue; 1473 //never clip against the back side 1474 if (hitnum == facet->numBorders - 1) continue; 1475 1476 if (enterFrac < leaveFrac && enterFrac >= 0) { 1477 if (enterFrac < tw->trace.fraction) { 1478 if (enterFrac < 0) { 1479 enterFrac = 0; 1480 } 1481 #ifndef BSPC 1482 if (!cv) { 1483 cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 ); 1484 } 1485 if (cv && cv->integer) { 1486 debugPatchCollide = pc; 1487 debugFacet = facet; 1488 } 1489 #endif //BSPC 1490 1491 tw->trace.fraction = enterFrac; 1492 VectorCopy( bestplane, tw->trace.plane.normal ); 1493 tw->trace.plane.dist = bestplane[3]; 1494 } 1495 } 1496 } 1497 } 1498 1499 1500 /* 1501 ======================================================================= 1502 1503 POSITION TEST 1504 1505 ======================================================================= 1506 */ 1507 1508 /* 1509 ==================== 1510 CM_PositionTestInPatchCollide 1511 ==================== 1512 */ 1513 qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) { 1514 int i, j; 1515 float offset, t; 1516 patchPlane_t *planes; 1517 facet_t *facet; 1518 float plane[4]; 1519 vec3_t startp; 1520 1521 if (tw->isPoint) { 1522 return qfalse; 1523 } 1524 // 1525 facet = pc->facets; 1526 for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) { 1527 planes = &pc->planes[ facet->surfacePlane ]; 1528 VectorCopy(planes->plane, plane); 1529 plane[3] = planes->plane[3]; 1530 if ( tw->sphere.use ) { 1531 // adjust the plane distance apropriately for radius 1532 plane[3] += tw->sphere.radius; 1533 1534 // find the closest point on the capsule to the plane 1535 t = DotProduct( plane, tw->sphere.offset ); 1536 if ( t > 0 ) { 1537 VectorSubtract( tw->start, tw->sphere.offset, startp ); 1538 } 1539 else { 1540 VectorAdd( tw->start, tw->sphere.offset, startp ); 1541 } 1542 } 1543 else { 1544 offset = DotProduct( tw->offsets[ planes->signbits ], plane); 1545 plane[3] -= offset; 1546 VectorCopy( tw->start, startp ); 1547 } 1548 1549 if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) { 1550 continue; 1551 } 1552 1553 for ( j = 0; j < facet->numBorders; j++ ) { 1554 planes = &pc->planes[ facet->borderPlanes[j] ]; 1555 if (facet->borderInward[j]) { 1556 VectorNegate(planes->plane, plane); 1557 plane[3] = -planes->plane[3]; 1558 } 1559 else { 1560 VectorCopy(planes->plane, plane); 1561 plane[3] = planes->plane[3]; 1562 } 1563 if ( tw->sphere.use ) { 1564 // adjust the plane distance apropriately for radius 1565 plane[3] += tw->sphere.radius; 1566 1567 // find the closest point on the capsule to the plane 1568 t = DotProduct( plane, tw->sphere.offset ); 1569 if ( t > 0.0f ) { 1570 VectorSubtract( tw->start, tw->sphere.offset, startp ); 1571 } 1572 else { 1573 VectorAdd( tw->start, tw->sphere.offset, startp ); 1574 } 1575 } 1576 else { 1577 // NOTE: this works even though the plane might be flipped because the bbox is centered 1578 offset = DotProduct( tw->offsets[ planes->signbits ], plane); 1579 plane[3] += fabs(offset); 1580 VectorCopy( tw->start, startp ); 1581 } 1582 1583 if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) { 1584 break; 1585 } 1586 } 1587 if (j < facet->numBorders) { 1588 continue; 1589 } 1590 // inside this patch facet 1591 return qtrue; 1592 } 1593 return qfalse; 1594 } 1595 1596 /* 1597 ======================================================================= 1598 1599 DEBUGGING 1600 1601 ======================================================================= 1602 */ 1603 1604 1605 /* 1606 ================== 1607 CM_DrawDebugSurface 1608 1609 Called from the renderer 1610 ================== 1611 */ 1612 #ifndef BSPC 1613 void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value); 1614 #endif 1615 1616 void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) { 1617 static cvar_t *cv; 1618 #ifndef BSPC 1619 static cvar_t *cv2; 1620 #endif 1621 const patchCollide_t *pc; 1622 facet_t *facet; 1623 winding_t *w; 1624 int i, j, k, n; 1625 int curplanenum, planenum, curinward, inward; 1626 float plane[4]; 1627 vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28}; 1628 //vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0}; 1629 vec3_t v1, v2; 1630 1631 #ifndef BSPC 1632 if ( !cv2 ) 1633 { 1634 cv2 = Cvar_Get( "r_debugSurface", "0", 0 ); 1635 } 1636 1637 if (cv2->integer != 1) 1638 { 1639 BotDrawDebugPolygons(drawPoly, cv2->integer); 1640 return; 1641 } 1642 #endif 1643 1644 if ( !debugPatchCollide ) { 1645 return; 1646 } 1647 1648 #ifndef BSPC 1649 if ( !cv ) { 1650 cv = Cvar_Get( "cm_debugSize", "2", 0 ); 1651 } 1652 #endif 1653 pc = debugPatchCollide; 1654 1655 for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) { 1656 1657 for ( k = 0 ; k < facet->numBorders + 1; k++ ) { 1658 // 1659 if (k < facet->numBorders) { 1660 planenum = facet->borderPlanes[k]; 1661 inward = facet->borderInward[k]; 1662 } 1663 else { 1664 planenum = facet->surfacePlane; 1665 inward = qfalse; 1666 //continue; 1667 } 1668 1669 Vector4Copy( pc->planes[ planenum ].plane, plane ); 1670 1671 //planenum = facet->surfacePlane; 1672 if ( inward ) { 1673 VectorSubtract( vec3_origin, plane, plane ); 1674 plane[3] = -plane[3]; 1675 } 1676 1677 plane[3] += cv->value; 1678 //* 1679 for (n = 0; n < 3; n++) 1680 { 1681 if (plane[n] > 0) v1[n] = maxs[n]; 1682 else v1[n] = mins[n]; 1683 } //end for 1684 VectorNegate(plane, v2); 1685 plane[3] += fabs(DotProduct(v1, v2)); 1686 //*/ 1687 1688 w = BaseWindingForPlane( plane, plane[3] ); 1689 for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) { 1690 // 1691 if (j < facet->numBorders) { 1692 curplanenum = facet->borderPlanes[j]; 1693 curinward = facet->borderInward[j]; 1694 } 1695 else { 1696 curplanenum = facet->surfacePlane; 1697 curinward = qfalse; 1698 //continue; 1699 } 1700 // 1701 if (curplanenum == planenum) continue; 1702 1703 Vector4Copy( pc->planes[ curplanenum ].plane, plane ); 1704 if ( !curinward ) { 1705 VectorSubtract( vec3_origin, plane, plane ); 1706 plane[3] = -plane[3]; 1707 } 1708 // if ( !facet->borderNoAdjust[j] ) { 1709 plane[3] -= cv->value; 1710 // } 1711 for (n = 0; n < 3; n++) 1712 { 1713 if (plane[n] > 0) v1[n] = maxs[n]; 1714 else v1[n] = mins[n]; 1715 } //end for 1716 VectorNegate(plane, v2); 1717 plane[3] -= fabs(DotProduct(v1, v2)); 1718 1719 ChopWindingInPlace( &w, plane, plane[3], 0.1f ); 1720 } 1721 if ( w ) { 1722 if ( facet == debugFacet ) { 1723 drawPoly( 4, w->numpoints, w->p[0] ); 1724 //Com_Printf("blue facet has %d border planes\n", facet->numBorders); 1725 } else { 1726 drawPoly( 1, w->numpoints, w->p[0] ); 1727 } 1728 FreeWinding( w ); 1729 } 1730 else 1731 Com_Printf("winding chopped away by border planes\n"); 1732 } 1733 } 1734 1735 // draw the debug block 1736 { 1737 vec3_t v[3]; 1738 1739 VectorCopy( debugBlockPoints[0], v[0] ); 1740 VectorCopy( debugBlockPoints[1], v[1] ); 1741 VectorCopy( debugBlockPoints[2], v[2] ); 1742 drawPoly( 2, 3, v[0] ); 1743 1744 VectorCopy( debugBlockPoints[2], v[0] ); 1745 VectorCopy( debugBlockPoints[3], v[1] ); 1746 VectorCopy( debugBlockPoints[0], v[2] ); 1747 drawPoly( 2, 3, v[0] ); 1748 } 1749 1750 #if 0 1751 vec3_t v[4]; 1752 1753 v[0][0] = pc->bounds[1][0]; 1754 v[0][1] = pc->bounds[1][1]; 1755 v[0][2] = pc->bounds[1][2]; 1756 1757 v[1][0] = pc->bounds[1][0]; 1758 v[1][1] = pc->bounds[0][1]; 1759 v[1][2] = pc->bounds[1][2]; 1760 1761 v[2][0] = pc->bounds[0][0]; 1762 v[2][1] = pc->bounds[0][1]; 1763 v[2][2] = pc->bounds[1][2]; 1764 1765 v[3][0] = pc->bounds[0][0]; 1766 v[3][1] = pc->bounds[1][1]; 1767 v[3][2] = pc->bounds[1][2]; 1768 1769 drawPoly( 4, v[0] ); 1770 #endif 1771 }