Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

cm_patch.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 #include "cm_local.h"
00024 #include "cm_patch.h"
00025 
00026 /*
00027 
00028 This file does not reference any globals, and has these entry points:
00029 
00030 void CM_ClearLevelPatches( void );
00031 struct patchCollide_s   *CM_GeneratePatchCollide( int width, int height, const vec3_t *points );
00032 void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
00033 qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
00034 void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );
00035 
00036 
00037 WARNING: this may misbehave with meshes that have rows or columns that only
00038 degenerate a few triangles.  Completely degenerate rows and columns are handled
00039 properly.
00040 */
00041 
00042 /*
00043 #define MAX_FACETS          1024
00044 #define MAX_PATCH_PLANES    2048
00045 
00046 typedef struct {
00047     float   plane[4];
00048     int     signbits;       // signx + (signy<<1) + (signz<<2), used as lookup during collision
00049 } patchPlane_t;
00050 
00051 typedef struct {
00052     int         surfacePlane;
00053     int         numBorders;     // 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels
00054     int         borderPlanes[4+6+16];
00055     int         borderInward[4+6+16];
00056     qboolean    borderNoAdjust[4+6+16];
00057 } facet_t;
00058 
00059 typedef struct patchCollide_s {
00060     vec3_t  bounds[2];
00061     int     numPlanes;          // surface planes plus edge planes
00062     patchPlane_t    *planes;
00063     int     numFacets;
00064     facet_t *facets;
00065 } patchCollide_t;
00066 
00067 
00068 #define MAX_GRID_SIZE   129
00069 
00070 typedef struct {
00071     int         width;
00072     int         height;
00073     qboolean    wrapWidth;
00074     qboolean    wrapHeight;
00075     vec3_t  points[MAX_GRID_SIZE][MAX_GRID_SIZE];   // [width][height]
00076 } cGrid_t;
00077 
00078 #define SUBDIVIDE_DISTANCE  16  //4 // never more than this units away from curve
00079 #define PLANE_TRI_EPSILON   0.1
00080 #define WRAP_POINT_EPSILON  0.1
00081 */
00082 
00083 int c_totalPatchBlocks;
00084 int c_totalPatchSurfaces;
00085 int c_totalPatchEdges;
00086 
00087 static const patchCollide_t *debugPatchCollide;
00088 static const facet_t        *debugFacet;
00089 static qboolean     debugBlock;
00090 static vec3_t       debugBlockPoints[4];
00091 
00092 /*
00093 =================
00094 CM_ClearLevelPatches
00095 =================
00096 */
00097 void CM_ClearLevelPatches( void ) {
00098     debugPatchCollide = NULL;
00099     debugFacet = NULL;
00100 }
00101 
00102 /*
00103 =================
00104 CM_SignbitsForNormal
00105 =================
00106 */
00107 static int CM_SignbitsForNormal( vec3_t normal ) {
00108     int bits, j;
00109 
00110     bits = 0;
00111     for (j=0 ; j<3 ; j++) {
00112         if ( normal[j] < 0 ) {
00113             bits |= 1<<j;
00114         }
00115     }
00116     return bits;
00117 }
00118 
00119 /*
00120 =====================
00121 CM_PlaneFromPoints
00122 
00123 Returns false if the triangle is degenrate.
00124 The normal will point out of the clock for clockwise ordered points
00125 =====================
00126 */
00127 static qboolean CM_PlaneFromPoints( vec4_t plane, vec3_t a, vec3_t b, vec3_t c ) {
00128     vec3_t  d1, d2;
00129 
00130     VectorSubtract( b, a, d1 );
00131     VectorSubtract( c, a, d2 );
00132     CrossProduct( d2, d1, plane );
00133     if ( VectorNormalize( plane ) == 0 ) {
00134         return qfalse;
00135     }
00136 
00137     plane[3] = DotProduct( a, plane );
00138     return qtrue;
00139 }
00140 
00141 
00142 /*
00143 ================================================================================
00144 
00145 GRID SUBDIVISION
00146 
00147 ================================================================================
00148 */
00149 
00150 /*
00151 =================
00152 CM_NeedsSubdivision
00153 
00154 Returns true if the given quadratic curve is not flat enough for our
00155 collision detection purposes
00156 =================
00157 */
00158 static qboolean CM_NeedsSubdivision( vec3_t a, vec3_t b, vec3_t c ) {
00159     vec3_t      cmid;
00160     vec3_t      lmid;
00161     vec3_t      delta;
00162     float       dist;
00163     int         i;
00164 
00165     // calculate the linear midpoint
00166     for ( i = 0 ; i < 3 ; i++ ) {
00167         lmid[i] = 0.5*(a[i] + c[i]);
00168     }
00169 
00170     // calculate the exact curve midpoint
00171     for ( i = 0 ; i < 3 ; i++ ) {
00172         cmid[i] = 0.5 * ( 0.5*(a[i] + b[i]) + 0.5*(b[i] + c[i]) );
00173     }
00174 
00175     // see if the curve is far enough away from the linear mid
00176     VectorSubtract( cmid, lmid, delta );
00177     dist = VectorLength( delta );
00178     
00179     return dist >= SUBDIVIDE_DISTANCE;
00180 }
00181 
00182 /*
00183 ===============
00184 CM_Subdivide
00185 
00186 a, b, and c are control points.
00187 the subdivided sequence will be: a, out1, out2, out3, c
00188 ===============
00189 */
00190 static void CM_Subdivide( vec3_t a, vec3_t b, vec3_t c, vec3_t out1, vec3_t out2, vec3_t out3 ) {
00191     int     i;
00192 
00193     for ( i = 0 ; i < 3 ; i++ ) {
00194         out1[i] = 0.5 * (a[i] + b[i]);
00195         out3[i] = 0.5 * (b[i] + c[i]);
00196         out2[i] = 0.5 * (out1[i] + out3[i]);
00197     }
00198 }
00199 
00200 /*
00201 =================
00202 CM_TransposeGrid
00203 
00204 Swaps the rows and columns in place
00205 =================
00206 */
00207 static void CM_TransposeGrid( cGrid_t *grid ) {
00208     int         i, j, l;
00209     vec3_t      temp;
00210     qboolean    tempWrap;
00211 
00212     if ( grid->width > grid->height ) {
00213         for ( i = 0 ; i < grid->height ; i++ ) {
00214             for ( j = i + 1 ; j < grid->width ; j++ ) {
00215                 if ( j < grid->height ) {
00216                     // swap the value
00217                     VectorCopy( grid->points[i][j], temp );
00218                     VectorCopy( grid->points[j][i], grid->points[i][j] );
00219                     VectorCopy( temp, grid->points[j][i] );
00220                 } else {
00221                     // just copy
00222                     VectorCopy( grid->points[j][i], grid->points[i][j] );
00223                 }
00224             }
00225         }
00226     } else {
00227         for ( i = 0 ; i < grid->width ; i++ ) {
00228             for ( j = i + 1 ; j < grid->height ; j++ ) {
00229                 if ( j < grid->width ) {
00230                     // swap the value
00231                     VectorCopy( grid->points[j][i], temp );
00232                     VectorCopy( grid->points[i][j], grid->points[j][i] );
00233                     VectorCopy( temp, grid->points[i][j] );
00234                 } else {
00235                     // just copy
00236                     VectorCopy( grid->points[i][j], grid->points[j][i] );
00237                 }
00238             }
00239         }
00240     }
00241 
00242     l = grid->width;
00243     grid->width = grid->height;
00244     grid->height = l;
00245 
00246     tempWrap = grid->wrapWidth;
00247     grid->wrapWidth = grid->wrapHeight;
00248     grid->wrapHeight = tempWrap;
00249 }
00250 
00251 /*
00252 ===================
00253 CM_SetGridWrapWidth
00254 
00255 If the left and right columns are exactly equal, set grid->wrapWidth qtrue
00256 ===================
00257 */
00258 static void CM_SetGridWrapWidth( cGrid_t *grid ) {
00259     int     i, j;
00260     float   d;
00261 
00262     for ( i = 0 ; i < grid->height ; i++ ) {
00263         for ( j = 0 ; j < 3 ; j++ ) {
00264             d = grid->points[0][i][j] - grid->points[grid->width-1][i][j];
00265             if ( d < -WRAP_POINT_EPSILON || d > WRAP_POINT_EPSILON ) {
00266                 break;
00267             }
00268         }
00269         if ( j != 3 ) {
00270             break;
00271         }
00272     }
00273     if ( i == grid->height ) {
00274         grid->wrapWidth = qtrue;
00275     } else {
00276         grid->wrapWidth = qfalse;
00277     }
00278 }
00279 
00280 /*
00281 =================
00282 CM_SubdivideGridColumns
00283 
00284 Adds columns as necessary to the grid until
00285 all the aproximating points are within SUBDIVIDE_DISTANCE
00286 from the true curve
00287 =================
00288 */
00289 static void CM_SubdivideGridColumns( cGrid_t *grid ) {
00290     int     i, j, k;
00291 
00292     for ( i = 0 ; i < grid->width - 2 ;  ) {
00293         // grid->points[i][x] is an interpolating control point
00294         // grid->points[i+1][x] is an aproximating control point
00295         // grid->points[i+2][x] is an interpolating control point
00296 
00297         //
00298         // first see if we can collapse the aproximating collumn away
00299         //
00300         for ( j = 0 ; j < grid->height ; j++ ) {
00301             if ( CM_NeedsSubdivision( grid->points[i][j], grid->points[i+1][j], grid->points[i+2][j] ) ) {
00302                 break;
00303             }
00304         }
00305         if ( j == grid->height ) {
00306             // all of the points were close enough to the linear midpoints
00307             // that we can collapse the entire column away
00308             for ( j = 0 ; j < grid->height ; j++ ) {
00309                 // remove the column
00310                 for ( k = i + 2 ; k < grid->width ; k++ ) {
00311                     VectorCopy( grid->points[k][j], grid->points[k-1][j] );
00312                 }
00313             }
00314 
00315             grid->width--;
00316 
00317             // go to the next curve segment
00318             i++;
00319             continue;
00320         }
00321 
00322         //
00323         // we need to subdivide the curve
00324         //
00325         for ( j = 0 ; j < grid->height ; j++ ) {
00326             vec3_t  prev, mid, next;
00327 
00328             // save the control points now
00329             VectorCopy( grid->points[i][j], prev );
00330             VectorCopy( grid->points[i+1][j], mid );
00331             VectorCopy( grid->points[i+2][j], next );
00332 
00333             // make room for two additional columns in the grid
00334             // columns i+1 will be replaced, column i+2 will become i+4
00335             // i+1, i+2, and i+3 will be generated
00336             for ( k = grid->width - 1 ; k > i + 1 ; k-- ) {
00337                 VectorCopy( grid->points[k][j], grid->points[k+2][j] );
00338             }
00339 
00340             // generate the subdivided points
00341             CM_Subdivide( prev, mid, next, grid->points[i+1][j], grid->points[i+2][j], grid->points[i+3][j] );
00342         }
00343 
00344         grid->width += 2;
00345 
00346         // the new aproximating point at i+1 may need to be removed
00347         // or subdivided farther, so don't advance i
00348     }
00349 }
00350 
00351 /*
00352 ======================
00353 CM_ComparePoints
00354 ======================
00355 */
00356 #define POINT_EPSILON   0.1
00357 static qboolean CM_ComparePoints( float *a, float *b ) {
00358     float       d;
00359 
00360     d = a[0] - b[0];
00361     if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
00362         return qfalse;
00363     }
00364     d = a[1] - b[1];
00365     if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
00366         return qfalse;
00367     }
00368     d = a[2] - b[2];
00369     if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
00370         return qfalse;
00371     }
00372     return qtrue;
00373 }
00374 
00375 /*
00376 =================
00377 CM_RemoveDegenerateColumns
00378 
00379 If there are any identical columns, remove them
00380 =================
00381 */
00382 static void CM_RemoveDegenerateColumns( cGrid_t *grid ) {
00383     int     i, j, k;
00384 
00385     for ( i = 0 ; i < grid->width - 1 ; i++ ) {
00386         for ( j = 0 ; j < grid->height ; j++ ) {
00387             if ( !CM_ComparePoints( grid->points[i][j], grid->points[i+1][j] ) ) {
00388                 break;
00389             }
00390         }
00391 
00392         if ( j != grid->height ) {
00393             continue;   // not degenerate
00394         }
00395 
00396         for ( j = 0 ; j < grid->height ; j++ ) {
00397             // remove the column
00398             for ( k = i + 2 ; k < grid->width ; k++ ) {
00399                 VectorCopy( grid->points[k][j], grid->points[k-1][j] );
00400             }
00401         }
00402         grid->width--;
00403 
00404         // check against the next column
00405         i--;
00406     }
00407 }
00408 
00409 /*
00410 ================================================================================
00411 
00412 PATCH COLLIDE GENERATION
00413 
00414 ================================================================================
00415 */
00416 
00417 static  int             numPlanes;
00418 static  patchPlane_t    planes[MAX_PATCH_PLANES];
00419 
00420 static  int             numFacets;
00421 static  facet_t         facets[MAX_PATCH_PLANES]; //maybe MAX_FACETS ??
00422 
00423 #define NORMAL_EPSILON  0.0001
00424 #define DIST_EPSILON    0.02
00425 
00426 /*
00427 ==================
00428 CM_PlaneEqual
00429 ==================
00430 */
00431 int CM_PlaneEqual(patchPlane_t *p, float plane[4], int *flipped) {
00432     float invplane[4];
00433 
00434     if (
00435        fabs(p->plane[0] - plane[0]) < NORMAL_EPSILON
00436     && fabs(p->plane[1] - plane[1]) < NORMAL_EPSILON
00437     && fabs(p->plane[2] - plane[2]) < NORMAL_EPSILON
00438     && fabs(p->plane[3] - plane[3]) < DIST_EPSILON )
00439     {
00440         *flipped = qfalse;
00441         return qtrue;
00442     }
00443 
00444     VectorNegate(plane, invplane);
00445     invplane[3] = -plane[3];
00446 
00447     if (
00448        fabs(p->plane[0] - invplane[0]) < NORMAL_EPSILON
00449     && fabs(p->plane[1] - invplane[1]) < NORMAL_EPSILON
00450     && fabs(p->plane[2] - invplane[2]) < NORMAL_EPSILON
00451     && fabs(p->plane[3] - invplane[3]) < DIST_EPSILON )
00452     {
00453         *flipped = qtrue;
00454         return qtrue;
00455     }
00456 
00457     return qfalse;
00458 }
00459 
00460 /*
00461 ==================
00462 CM_SnapVector
00463 ==================
00464 */
00465 void CM_SnapVector(vec3_t normal) {
00466     int     i;
00467 
00468     for (i=0 ; i<3 ; i++)
00469     {
00470         if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
00471         {
00472             VectorClear (normal);
00473             normal[i] = 1;
00474             break;
00475         }
00476         if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
00477         {
00478             VectorClear (normal);
00479             normal[i] = -1;
00480             break;
00481         }
00482     }
00483 }
00484 
00485 /*
00486 ==================
00487 CM_FindPlane2
00488 ==================
00489 */
00490 int CM_FindPlane2(float plane[4], int *flipped) {
00491     int i;
00492 
00493     // see if the points are close enough to an existing plane
00494     for ( i = 0 ; i < numPlanes ; i++ ) {
00495         if (CM_PlaneEqual(&planes[i], plane, flipped)) return i;
00496     }
00497 
00498     // add a new plane
00499     if ( numPlanes == MAX_PATCH_PLANES ) {
00500         Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
00501     }
00502 
00503     Vector4Copy( plane, planes[numPlanes].plane );
00504     planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
00505 
00506     numPlanes++;
00507 
00508     *flipped = qfalse;
00509 
00510     return numPlanes-1;
00511 }
00512 
00513 /*
00514 ==================
00515 CM_FindPlane
00516 ==================
00517 */
00518 static int CM_FindPlane( float *p1, float *p2, float *p3 ) {
00519     float   plane[4];
00520     int     i;
00521     float   d;
00522 
00523     if ( !CM_PlaneFromPoints( plane, p1, p2, p3 ) ) {
00524         return -1;
00525     }
00526 
00527     // see if the points are close enough to an existing plane
00528     for ( i = 0 ; i < numPlanes ; i++ ) {
00529         if ( DotProduct( plane, planes[i].plane ) < 0 ) {
00530             continue;   // allow backwards planes?
00531         }
00532 
00533         d = DotProduct( p1, planes[i].plane ) - planes[i].plane[3];
00534         if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
00535             continue;
00536         }
00537 
00538         d = DotProduct( p2, planes[i].plane ) - planes[i].plane[3];
00539         if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
00540             continue;
00541         }
00542 
00543         d = DotProduct( p3, planes[i].plane ) - planes[i].plane[3];
00544         if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
00545             continue;
00546         }
00547 
00548         // found it
00549         return i;
00550     }
00551 
00552     // add a new plane
00553     if ( numPlanes == MAX_PATCH_PLANES ) {
00554         Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
00555     }
00556 
00557     Vector4Copy( plane, planes[numPlanes].plane );
00558     planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
00559 
00560     numPlanes++;
00561 
00562     return numPlanes-1;
00563 }
00564 
00565 /*
00566 ==================
00567 CM_PointOnPlaneSide
00568 ==================
00569 */
00570 static int CM_PointOnPlaneSide( float *p, int planeNum ) {
00571     float   *plane;
00572     float   d;
00573 
00574     if ( planeNum == -1 ) {
00575         return SIDE_ON;
00576     }
00577     plane = planes[ planeNum ].plane;
00578 
00579     d = DotProduct( p, plane ) - plane[3];
00580 
00581     if ( d > PLANE_TRI_EPSILON ) {
00582         return SIDE_FRONT;
00583     }
00584 
00585     if ( d < -PLANE_TRI_EPSILON ) {
00586         return SIDE_BACK;
00587     }
00588 
00589     return SIDE_ON;
00590 }
00591 
00592 /*
00593 ==================
00594 CM_GridPlane
00595 ==================
00596 */
00597 static int  CM_GridPlane( int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int tri ) {
00598     int     p;
00599 
00600     p = gridPlanes[i][j][tri];
00601     if ( p != -1 ) {
00602         return p;
00603     }
00604     p = gridPlanes[i][j][!tri];
00605     if ( p != -1 ) {
00606         return p;
00607     }
00608 
00609     // should never happen
00610     Com_Printf( "WARNING: CM_GridPlane unresolvable\n" );
00611     return -1;
00612 }
00613 
00614 /*
00615 ==================
00616 CM_EdgePlaneNum
00617 ==================
00618 */
00619 static int CM_EdgePlaneNum( cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int k ) {
00620     float   *p1, *p2;
00621     vec3_t      up;
00622     int         p;
00623 
00624     switch ( k ) {
00625     case 0: // top border
00626         p1 = grid->points[i][j];
00627         p2 = grid->points[i+1][j];
00628         p = CM_GridPlane( gridPlanes, i, j, 0 );
00629         VectorMA( p1, 4, planes[ p ].plane, up );
00630         return CM_FindPlane( p1, p2, up );
00631 
00632     case 2: // bottom border
00633         p1 = grid->points[i][j+1];
00634         p2 = grid->points[i+1][j+1];
00635         p = CM_GridPlane( gridPlanes, i, j, 1 );
00636         VectorMA( p1, 4, planes[ p ].plane, up );
00637         return CM_FindPlane( p2, p1, up );
00638 
00639     case 3: // left border
00640         p1 = grid->points[i][j];
00641         p2 = grid->points[i][j+1];
00642         p = CM_GridPlane( gridPlanes, i, j, 1 );
00643         VectorMA( p1, 4, planes[ p ].plane, up );
00644         return CM_FindPlane( p2, p1, up );
00645 
00646     case 1: // right border
00647         p1 = grid->points[i+1][j];
00648         p2 = grid->points[i+1][j+1];
00649         p = CM_GridPlane( gridPlanes, i, j, 0 );
00650         VectorMA( p1, 4, planes[ p ].plane, up );
00651         return CM_FindPlane( p1, p2, up );
00652 
00653     case 4: // diagonal out of triangle 0
00654         p1 = grid->points[i+1][j+1];
00655         p2 = grid->points[i][j];
00656         p = CM_GridPlane( gridPlanes, i, j, 0 );
00657         VectorMA( p1, 4, planes[ p ].plane, up );
00658         return CM_FindPlane( p1, p2, up );
00659 
00660     case 5: // diagonal out of triangle 1
00661         p1 = grid->points[i][j];
00662         p2 = grid->points[i+1][j+1];
00663         p = CM_GridPlane( gridPlanes, i, j, 1 );
00664         VectorMA( p1, 4, planes[ p ].plane, up );
00665         return CM_FindPlane( p1, p2, up );
00666 
00667     }
00668 
00669     Com_Error( ERR_DROP, "CM_EdgePlaneNum: bad k" );
00670     return -1;
00671 }
00672 
00673 /*
00674 ===================
00675 CM_SetBorderInward
00676 ===================
00677 */
00678 static void CM_SetBorderInward( facet_t *facet, cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2],
00679                           int i, int j, int which ) {
00680     int     k, l;
00681     float   *points[4];
00682     int     numPoints;
00683 
00684     switch ( which ) {
00685     case -1:
00686         points[0] = grid->points[i][j];
00687         points[1] = grid->points[i+1][j];
00688         points[2] = grid->points[i+1][j+1];
00689         points[3] = grid->points[i][j+1];
00690         numPoints = 4;
00691         break;
00692     case 0:
00693         points[0] = grid->points[i][j];
00694         points[1] = grid->points[i+1][j];
00695         points[2] = grid->points[i+1][j+1];
00696         numPoints = 3;
00697         break;
00698     case 1:
00699         points[0] = grid->points[i+1][j+1];
00700         points[1] = grid->points[i][j+1];
00701         points[2] = grid->points[i][j];
00702         numPoints = 3;
00703         break;
00704     default:
00705         Com_Error( ERR_FATAL, "CM_SetBorderInward: bad parameter" );
00706         numPoints = 0;
00707         break;
00708     }
00709 
00710     for ( k = 0 ; k < facet->numBorders ; k++ ) {
00711         int     front, back;
00712 
00713         front = 0;
00714         back = 0;
00715 
00716         for ( l = 0 ; l < numPoints ; l++ ) {
00717             int     side;
00718 
00719             side = CM_PointOnPlaneSide( points[l], facet->borderPlanes[k] );
00720             if ( side == SIDE_FRONT ) {
00721                 front++;
00722             } if ( side == SIDE_BACK ) {
00723                 back++;
00724             }
00725         }
00726 
00727         if ( front && !back ) {
00728             facet->borderInward[k] = qtrue;
00729         } else if ( back && !front ) {
00730             facet->borderInward[k] = qfalse;
00731         } else if ( !front && !back ) {
00732             // flat side border
00733             facet->borderPlanes[k] = -1;
00734         } else {
00735             // bisecting side border
00736             Com_DPrintf( "WARNING: CM_SetBorderInward: mixed plane sides\n" );
00737             facet->borderInward[k] = qfalse;
00738             if ( !debugBlock ) {
00739                 debugBlock = qtrue;
00740                 VectorCopy( grid->points[i][j], debugBlockPoints[0] );
00741                 VectorCopy( grid->points[i+1][j], debugBlockPoints[1] );
00742                 VectorCopy( grid->points[i+1][j+1], debugBlockPoints[2] );
00743                 VectorCopy( grid->points[i][j+1], debugBlockPoints[3] );
00744             }
00745         }
00746     }
00747 }
00748 
00749 /*
00750 ==================
00751 CM_ValidateFacet
00752 
00753 If the facet isn't bounded by its borders, we screwed up.
00754 ==================
00755 */
00756 static qboolean CM_ValidateFacet( facet_t *facet ) {
00757     float       plane[4];
00758     int         j;
00759     winding_t   *w;
00760     vec3_t      bounds[2];
00761 
00762     if ( facet->surfacePlane == -1 ) {
00763         return qfalse;
00764     }
00765 
00766     Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
00767     w = BaseWindingForPlane( plane,  plane[3] );
00768     for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
00769         if ( facet->borderPlanes[j] == -1 ) {
00770             return qfalse;
00771         }
00772         Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
00773         if ( !facet->borderInward[j] ) {
00774             VectorSubtract( vec3_origin, plane, plane );
00775             plane[3] = -plane[3];
00776         }
00777         ChopWindingInPlace( &w, plane, plane[3], 0.1f );
00778     }
00779 
00780     if ( !w ) {
00781         return qfalse;      // winding was completely chopped away
00782     }
00783 
00784     // see if the facet is unreasonably large
00785     WindingBounds( w, bounds[0], bounds[1] );
00786     FreeWinding( w );
00787     
00788     for ( j = 0 ; j < 3 ; j++ ) {
00789         if ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) {
00790             return qfalse;      // we must be missing a plane
00791         }
00792         if ( bounds[0][j] >= MAX_MAP_BOUNDS ) {
00793             return qfalse;
00794         }
00795         if ( bounds[1][j] <= -MAX_MAP_BOUNDS ) {
00796             return qfalse;
00797         }
00798     }
00799     return qtrue;       // winding is fine
00800 }
00801 
00802 /*
00803 ==================
00804 CM_AddFacetBevels
00805 ==================
00806 */
00807 void CM_AddFacetBevels( facet_t *facet ) {
00808 
00809     int i, j, k, l;
00810     int axis, dir, order, flipped;
00811     float plane[4], d, newplane[4];
00812     winding_t *w, *w2;
00813     vec3_t mins, maxs, vec, vec2;
00814 
00815     Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
00816 
00817     w = BaseWindingForPlane( plane,  plane[3] );
00818     for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
00819         if (facet->borderPlanes[j] == facet->surfacePlane) continue;
00820         Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
00821 
00822         if ( !facet->borderInward[j] ) {
00823             VectorSubtract( vec3_origin, plane, plane );
00824             plane[3] = -plane[3];
00825         }
00826 
00827         ChopWindingInPlace( &w, plane, plane[3], 0.1f );
00828     }
00829     if ( !w ) {
00830         return;
00831     }
00832 
00833     WindingBounds(w, mins, maxs);
00834 
00835     // add the axial planes
00836     order = 0;
00837     for ( axis = 0 ; axis < 3 ; axis++ )
00838     {
00839         for ( dir = -1 ; dir <= 1 ; dir += 2, order++ )
00840         {
00841             VectorClear(plane);
00842             plane[axis] = dir;
00843             if (dir == 1) {
00844                 plane[3] = maxs[axis];
00845             }
00846             else {
00847                 plane[3] = -mins[axis];
00848             }
00849             //if it's the surface plane
00850             if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
00851                 continue;
00852             }
00853             // see if the plane is allready present
00854             for ( i = 0 ; i < facet->numBorders ; i++ ) {
00855                 if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped))
00856                     break;
00857             }
00858 
00859             if ( i == facet->numBorders ) {
00860                 if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
00861                 facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
00862                 facet->borderNoAdjust[facet->numBorders] = 0;
00863                 facet->borderInward[facet->numBorders] = flipped;
00864                 facet->numBorders++;
00865             }
00866         }
00867     }
00868     //
00869     // add the edge bevels
00870     //
00871     // test the non-axial plane edges
00872     for ( j = 0 ; j < w->numpoints ; j++ )
00873     {
00874         k = (j+1)%w->numpoints;
00875         VectorSubtract (w->p[j], w->p[k], vec);
00876         //if it's a degenerate edge
00877         if (VectorNormalize (vec) < 0.5)
00878             continue;
00879         CM_SnapVector(vec);
00880         for ( k = 0; k < 3 ; k++ )
00881             if ( vec[k] == -1 || vec[k] == 1 )
00882                 break;  // axial
00883         if ( k < 3 )
00884             continue;   // only test non-axial edges
00885 
00886         // try the six possible slanted axials from this edge
00887         for ( axis = 0 ; axis < 3 ; axis++ )
00888         {
00889             for ( dir = -1 ; dir <= 1 ; dir += 2 )
00890             {
00891                 // construct a plane
00892                 VectorClear (vec2);
00893                 vec2[axis] = dir;
00894                 CrossProduct (vec, vec2, plane);
00895                 if (VectorNormalize (plane) < 0.5)
00896                     continue;
00897                 plane[3] = DotProduct (w->p[j], plane);
00898 
00899                 // if all the points of the facet winding are
00900                 // behind this plane, it is a proper edge bevel
00901                 for ( l = 0 ; l < w->numpoints ; l++ )
00902                 {
00903                     d = DotProduct (w->p[l], plane) - plane[3];
00904                     if (d > 0.1)
00905                         break;  // point in front
00906                 }
00907                 if ( l < w->numpoints )
00908                     continue;
00909 
00910                 //if it's the surface plane
00911                 if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
00912                     continue;
00913                 }
00914                 // see if the plane is allready present
00915                 for ( i = 0 ; i < facet->numBorders ; i++ ) {
00916                     if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) {
00917                             break;
00918                     }
00919                 }
00920 
00921                 if ( i == facet->numBorders ) {
00922                     if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
00923                     facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
00924 
00925                     for ( k = 0 ; k < facet->numBorders ; k++ ) {
00926                         if (facet->borderPlanes[facet->numBorders] ==
00927                             facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n");
00928                     }
00929 
00930                     facet->borderNoAdjust[facet->numBorders] = 0;
00931                     facet->borderInward[facet->numBorders] = flipped;
00932                     //
00933                     w2 = CopyWinding(w);
00934                     Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane);
00935                     if (!facet->borderInward[facet->numBorders])
00936                     {
00937                         VectorNegate(newplane, newplane);
00938                         newplane[3] = -newplane[3];
00939                     } //end if
00940                     ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
00941                     if (!w2) {
00942                         Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
00943                         continue;
00944                     }
00945                     else {
00946                         FreeWinding(w2);
00947                     }
00948                     //
00949                     facet->numBorders++;
00950                     //already got a bevel
00951 //                  break;
00952                 }
00953             }
00954         }
00955     }
00956     FreeWinding( w );
00957 
00958 #ifndef BSPC
00959     //add opposite plane
00960     facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
00961     facet->borderNoAdjust[facet->numBorders] = 0;
00962     facet->borderInward[facet->numBorders] = qtrue;
00963     facet->numBorders++;
00964 #endif //BSPC
00965 
00966 }
00967 
00968 typedef enum {
00969     EN_TOP,
00970     EN_RIGHT,
00971     EN_BOTTOM,
00972     EN_LEFT
00973 } edgeName_t;
00974 
00975 /*
00976 ==================
00977 CM_PatchCollideFromGrid
00978 ==================
00979 */
00980 static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) {
00981     int             i, j;
00982     float           *p1, *p2, *p3;
00983     MAC_STATIC int              gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2];
00984     facet_t         *facet;
00985     int             borders[4];
00986     int             noAdjust[4];
00987 
00988     numPlanes = 0;
00989     numFacets = 0;
00990 
00991     // find the planes for each triangle of the grid
00992     for ( i = 0 ; i < grid->width - 1 ; i++ ) {
00993         for ( j = 0 ; j < grid->height - 1 ; j++ ) {
00994             p1 = grid->points[i][j];
00995             p2 = grid->points[i+1][j];
00996             p3 = grid->points[i+1][j+1];
00997             gridPlanes[i][j][0] = CM_FindPlane( p1, p2, p3 );
00998 
00999             p1 = grid->points[i+1][j+1];
01000             p2 = grid->points[i][j+1];
01001             p3 = grid->points[i][j];
01002             gridPlanes[i][j][1] = CM_FindPlane( p1, p2, p3 );
01003         }
01004     }
01005 
01006     // create the borders for each facet
01007     for ( i = 0 ; i < grid->width - 1 ; i++ ) {
01008         for ( j = 0 ; j < grid->height - 1 ; j++ ) {
01009              
01010             borders[EN_TOP] = -1;
01011             if ( j > 0 ) {
01012                 borders[EN_TOP] = gridPlanes[i][j-1][1];
01013             } else if ( grid->wrapHeight ) {
01014                 borders[EN_TOP] = gridPlanes[i][grid->height-2][1];
01015             } 
01016             noAdjust[EN_TOP] = ( borders[EN_TOP] == gridPlanes[i][j][0] );
01017             if ( borders[EN_TOP] == -1 || noAdjust[EN_TOP] ) {
01018                 borders[EN_TOP] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 0 );
01019             }
01020 
01021             borders[EN_BOTTOM] = -1;
01022             if ( j < grid->height - 2 ) {
01023                 borders[EN_BOTTOM] = gridPlanes[i][j+1][0];
01024             } else if ( grid->wrapHeight ) {
01025                 borders[EN_BOTTOM] = gridPlanes[i][0][0];
01026             }
01027             noAdjust[EN_BOTTOM] = ( borders[EN_BOTTOM] == gridPlanes[i][j][1] );
01028             if ( borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM] ) {
01029                 borders[EN_BOTTOM] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 2 );
01030             }
01031 
01032             borders[EN_LEFT] = -1;
01033             if ( i > 0 ) {
01034                 borders[EN_LEFT] = gridPlanes[i-1][j][0];
01035             } else if ( grid->wrapWidth ) {
01036                 borders[EN_LEFT] = gridPlanes[grid->width-2][j][0];
01037             }
01038             noAdjust[EN_LEFT] = ( borders[EN_LEFT] == gridPlanes[i][j][1] );
01039             if ( borders[EN_LEFT] == -1 || noAdjust[EN_LEFT] ) {
01040                 borders[EN_LEFT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 3 );
01041             }
01042 
01043             borders[EN_RIGHT] = -1;
01044             if ( i < grid->width - 2 ) {
01045                 borders[EN_RIGHT] = gridPlanes[i+1][j][1];
01046             } else if ( grid->wrapWidth ) {
01047                 borders[EN_RIGHT] = gridPlanes[0][j][1];
01048             }
01049             noAdjust[EN_RIGHT] = ( borders[EN_RIGHT] == gridPlanes[i][j][0] );
01050             if ( borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT] ) {
01051                 borders[EN_RIGHT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 1 );
01052             }
01053 
01054             if ( numFacets == MAX_FACETS ) {
01055                 Com_Error( ERR_DROP, "MAX_FACETS" );
01056             }
01057             facet = &facets[numFacets];
01058             Com_Memset( facet, 0, sizeof( *facet ) );
01059 
01060             if ( gridPlanes[i][j][0] == gridPlanes[i][j][1] ) {
01061                 if ( gridPlanes[i][j][0] == -1 ) {
01062                     continue;       // degenrate
01063                 }
01064                 facet->surfacePlane = gridPlanes[i][j][0];
01065                 facet->numBorders = 4;
01066                 facet->borderPlanes[0] = borders[EN_TOP];
01067                 facet->borderNoAdjust[0] = noAdjust[EN_TOP];
01068                 facet->borderPlanes[1] = borders[EN_RIGHT];
01069                 facet->borderNoAdjust[1] = noAdjust[EN_RIGHT];
01070                 facet->borderPlanes[2] = borders[EN_BOTTOM];
01071                 facet->borderNoAdjust[2] = noAdjust[EN_BOTTOM];
01072                 facet->borderPlanes[3] = borders[EN_LEFT];
01073                 facet->borderNoAdjust[3] = noAdjust[EN_LEFT];
01074                 CM_SetBorderInward( facet, grid, gridPlanes, i, j, -1 );
01075                 if ( CM_ValidateFacet( facet ) ) {
01076                     CM_AddFacetBevels( facet );
01077                     numFacets++;
01078                 }
01079             } else {
01080                 // two seperate triangles
01081                 facet->surfacePlane = gridPlanes[i][j][0];
01082                 facet->numBorders = 3;
01083                 facet->borderPlanes[0] = borders[EN_TOP];
01084                 facet->borderNoAdjust[0] = noAdjust[EN_TOP];
01085                 facet->borderPlanes[1] = borders[EN_RIGHT];
01086                 facet->borderNoAdjust[1] = noAdjust[EN_RIGHT];
01087                 facet->borderPlanes[2] = gridPlanes[i][j][1];
01088                 if ( facet->borderPlanes[2] == -1 ) {
01089                     facet->borderPlanes[2] = borders[EN_BOTTOM];
01090                     if ( facet->borderPlanes[2] == -1 ) {
01091                         facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 4 );
01092                     }
01093                 }
01094                 CM_SetBorderInward( facet, grid, gridPlanes, i, j, 0 );
01095                 if ( CM_ValidateFacet( facet ) ) {
01096                     CM_AddFacetBevels( facet );
01097                     numFacets++;
01098                 }
01099 
01100                 if ( numFacets == MAX_FACETS ) {
01101                     Com_Error( ERR_DROP, "MAX_FACETS" );
01102                 }
01103                 facet = &facets[numFacets];
01104                 Com_Memset( facet, 0, sizeof( *facet ) );
01105 
01106                 facet->surfacePlane = gridPlanes[i][j][1];
01107                 facet->numBorders = 3;
01108                 facet->borderPlanes[0] = borders[EN_BOTTOM];
01109                 facet->borderNoAdjust[0] = noAdjust[EN_BOTTOM];
01110                 facet->borderPlanes[1] = borders[EN_LEFT];
01111                 facet->borderNoAdjust[1] = noAdjust[EN_LEFT];
01112                 facet->borderPlanes[2] = gridPlanes[i][j][0];
01113                 if ( facet->borderPlanes[2] == -1 ) {
01114                     facet->borderPlanes[2] = borders[EN_TOP];
01115                     if ( facet->borderPlanes[2] == -1 ) {
01116                         facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 5 );
01117                     }
01118                 }
01119                 CM_SetBorderInward( facet, grid, gridPlanes, i, j, 1 );
01120                 if ( CM_ValidateFacet( facet ) ) {
01121                     CM_AddFacetBevels( facet );
01122                     numFacets++;
01123                 }
01124             }
01125         }
01126     }
01127 
01128     // copy the results out
01129     pf->numPlanes = numPlanes;
01130     pf->numFacets = numFacets;
01131     pf->facets = Hunk_Alloc( numFacets * sizeof( *pf->facets ), h_high );
01132     Com_Memcpy( pf->facets, facets, numFacets * sizeof( *pf->facets ) );
01133     pf->planes = Hunk_Alloc( numPlanes * sizeof( *pf->planes ), h_high );
01134     Com_Memcpy( pf->planes, planes, numPlanes * sizeof( *pf->planes ) );
01135 }
01136 
01137 
01138 /*
01139 ===================
01140 CM_GeneratePatchCollide
01141 
01142 Creates an internal structure that will be used to perform
01143 collision detection with a patch mesh.
01144 
01145 Points is packed as concatenated rows.
01146 ===================
01147 */
01148 struct patchCollide_s   *CM_GeneratePatchCollide( int width, int height, vec3_t *points ) {
01149     patchCollide_t  *pf;
01150     MAC_STATIC cGrid_t          grid;
01151     int             i, j;
01152 
01153     if ( width <= 2 || height <= 2 || !points ) {
01154         Com_Error( ERR_DROP, "CM_GeneratePatchFacets: bad parameters: (%i, %i, %p)",
01155             width, height, points );
01156     }
01157 
01158     if ( !(width & 1) || !(height & 1) ) {
01159         Com_Error( ERR_DROP, "CM_GeneratePatchFacets: even sizes are invalid for quadratic meshes" );
01160     }
01161 
01162     if ( width > MAX_GRID_SIZE || height > MAX_GRID_SIZE ) {
01163         Com_Error( ERR_DROP, "CM_GeneratePatchFacets: source is > MAX_GRID_SIZE" );
01164     }
01165 
01166     // build a grid
01167     grid.width = width;
01168     grid.height = height;
01169     grid.wrapWidth = qfalse;
01170     grid.wrapHeight = qfalse;
01171     for ( i = 0 ; i < width ; i++ ) {
01172         for ( j = 0 ; j < height ; j++ ) {
01173             VectorCopy( points[j*width + i], grid.points[i][j] );
01174         }
01175     }
01176 
01177     // subdivide the grid
01178     CM_SetGridWrapWidth( &grid );
01179     CM_SubdivideGridColumns( &grid );
01180     CM_RemoveDegenerateColumns( &grid );
01181 
01182     CM_TransposeGrid( &grid );
01183 
01184     CM_SetGridWrapWidth( &grid );
01185     CM_SubdivideGridColumns( &grid );
01186     CM_RemoveDegenerateColumns( &grid );
01187 
01188     // we now have a grid of points exactly on the curve
01189     // the aproximate surface defined by these points will be
01190     // collided against
01191     pf = Hunk_Alloc( sizeof( *pf ), h_high );
01192     ClearBounds( pf->bounds[0], pf->bounds[1] );
01193     for ( i = 0 ; i < grid.width ; i++ ) {
01194         for ( j = 0 ; j < grid.height ; j++ ) {
01195             AddPointToBounds( grid.points[i][j], pf->bounds[0], pf->bounds[1] );
01196         }
01197     }
01198 
01199     c_totalPatchBlocks += ( grid.width - 1 ) * ( grid.height - 1 );
01200 
01201     // generate a bsp tree for the surface
01202     CM_PatchCollideFromGrid( &grid, pf );
01203 
01204     // expand by one unit for epsilon purposes
01205     pf->bounds[0][0] -= 1;
01206     pf->bounds[0][1] -= 1;
01207     pf->bounds[0][2] -= 1;
01208 
01209     pf->bounds[1][0] += 1;
01210     pf->bounds[1][1] += 1;
01211     pf->bounds[1][2] += 1;
01212 
01213     return pf;
01214 }
01215 
01216 /*
01217 ================================================================================
01218 
01219 TRACE TESTING
01220 
01221 ================================================================================
01222 */
01223 
01224 /*
01225 ====================
01226 CM_TracePointThroughPatchCollide
01227 
01228   special case for point traces because the patch collide "brushes" have no volume
01229 ====================
01230 */
01231 void CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
01232     qboolean    frontFacing[MAX_PATCH_PLANES];
01233     float       intersection[MAX_PATCH_PLANES];
01234     float       intersect;
01235     const patchPlane_t  *planes;
01236     const facet_t   *facet;
01237     int         i, j, k;
01238     float       offset;
01239     float       d1, d2;
01240 #ifndef BSPC
01241     static cvar_t *cv;
01242 #endif //BSPC
01243 
01244 #ifndef BSPC
01245     if ( !cm_playerCurveClip->integer || !tw->isPoint ) {
01246         return;
01247     }
01248 #endif
01249 
01250     // determine the trace's relationship to all planes
01251     planes = pc->planes;
01252     for ( i = 0 ; i < pc->numPlanes ; i++, planes++ ) {
01253         offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
01254         d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
01255         d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
01256         if ( d1 <= 0 ) {
01257             frontFacing[i] = qfalse;
01258         } else {
01259             frontFacing[i] = qtrue;
01260         }
01261         if ( d1 == d2 ) {
01262             intersection[i] = 99999;
01263         } else {
01264             intersection[i] = d1 / ( d1 - d2 );
01265             if ( intersection[i] <= 0 ) {
01266                 intersection[i] = 99999;
01267             }
01268         }
01269     }
01270 
01271 
01272     // see if any of the surface planes are intersected
01273     facet = pc->facets;
01274     for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
01275         if ( !frontFacing[facet->surfacePlane] ) {
01276             continue;
01277         }
01278         intersect = intersection[facet->surfacePlane];
01279         if ( intersect < 0 ) {
01280             continue;       // surface is behind the starting point
01281         }
01282         if ( intersect > tw->trace.fraction ) {
01283             continue;       // already hit something closer
01284         }
01285         for ( j = 0 ; j < facet->numBorders ; j++ ) {
01286             k = facet->borderPlanes[j];
01287             if ( frontFacing[k] ^ facet->borderInward[j] ) {
01288                 if ( intersection[k] > intersect ) {
01289                     break;
01290                 }
01291             } else {
01292                 if ( intersection[k] < intersect ) {
01293                     break;
01294                 }
01295             }
01296         }
01297         if ( j == facet->numBorders ) {
01298             // we hit this facet
01299 #ifndef BSPC
01300             if (!cv) {
01301                 cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
01302             }
01303             if (cv->integer) {
01304                 debugPatchCollide = pc;
01305                 debugFacet = facet;
01306             }
01307 #endif //BSPC
01308             planes = &pc->planes[facet->surfacePlane];
01309 
01310             // calculate intersection with a slight pushoff
01311             offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
01312             d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
01313             d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
01314             tw->trace.fraction = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
01315 
01316             if ( tw->trace.fraction < 0 ) {
01317                 tw->trace.fraction = 0;
01318             }
01319 
01320             VectorCopy( planes->plane,  tw->trace.plane.normal );
01321             tw->trace.plane.dist = planes->plane[3];
01322         }
01323     }
01324 }
01325 
01326 /*
01327 ====================
01328 CM_CheckFacetPlane
01329 ====================
01330 */
01331 int CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, float *leaveFrac, int *hit) {
01332     float d1, d2, f;
01333 
01334     *hit = qfalse;
01335 
01336     d1 = DotProduct( start, plane ) - plane[3];
01337     d2 = DotProduct( end, plane ) - plane[3];
01338 
01339     // if completely in front of face, no intersection with the entire facet
01340     if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {
01341         return qfalse;
01342     }
01343 
01344     // if it doesn't cross the plane, the plane isn't relevent
01345     if (d1 <= 0 && d2 <= 0 ) {
01346         return qtrue;
01347     }
01348 
01349     // crosses face
01350     if (d1 > d2) {  // enter
01351         f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
01352         if ( f < 0 ) {
01353             f = 0;
01354         }
01355         //always favor previous plane hits and thus also the surface plane hit
01356         if (f > *enterFrac) {
01357             *enterFrac = f;
01358             *hit = qtrue;
01359         }
01360     } else {    // leave
01361         f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
01362         if ( f > 1 ) {
01363             f = 1;
01364         }
01365         if (f < *leaveFrac) {
01366             *leaveFrac = f;
01367         }
01368     }
01369     return qtrue;
01370 }
01371 
01372 /*
01373 ====================
01374 CM_TraceThroughPatchCollide
01375 ====================
01376 */
01377 void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
01378     int i, j, hit, hitnum;
01379     float offset, enterFrac, leaveFrac, t;
01380     patchPlane_t *planes;
01381     facet_t *facet;
01382     float plane[4], bestplane[4];
01383     vec3_t startp, endp;
01384 #ifndef BSPC
01385     static cvar_t *cv;
01386 #endif //BSPC
01387 
01388     if (tw->isPoint) {
01389         CM_TracePointThroughPatchCollide( tw, pc );
01390         return;
01391     }
01392 
01393     facet = pc->facets;
01394     for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
01395         enterFrac = -1.0;
01396         leaveFrac = 1.0;
01397         hitnum = -1;
01398         //
01399         planes = &pc->planes[ facet->surfacePlane ];
01400         VectorCopy(planes->plane, plane);
01401         plane[3] = planes->plane[3];
01402         if ( tw->sphere.use ) {
01403             // adjust the plane distance apropriately for radius
01404             plane[3] += tw->sphere.radius;
01405 
01406             // find the closest point on the capsule to the plane
01407             t = DotProduct( plane, tw->sphere.offset );
01408             if ( t > 0.0f ) {
01409                 VectorSubtract( tw->start, tw->sphere.offset, startp );
01410                 VectorSubtract( tw->end, tw->sphere.offset, endp );
01411             }
01412             else {
01413                 VectorAdd( tw->start, tw->sphere.offset, startp );
01414                 VectorAdd( tw->end, tw->sphere.offset, endp );
01415             }
01416         }
01417         else {
01418             offset = DotProduct( tw->offsets[ planes->signbits ], plane);
01419             plane[3] -= offset;
01420             VectorCopy( tw->start, startp );
01421             VectorCopy( tw->end, endp );
01422         }
01423 
01424         if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
01425             continue;
01426         }
01427         if (hit) {
01428             Vector4Copy(plane, bestplane);
01429         }
01430 
01431         for ( j = 0; j < facet->numBorders; j++ ) {
01432             planes = &pc->planes[ facet->borderPlanes[j] ];
01433             if (facet->borderInward[j]) {
01434                 VectorNegate(planes->plane, plane);
01435                 plane[3] = -planes->plane[3];
01436             }
01437             else {
01438                 VectorCopy(planes->plane, plane);
01439                 plane[3] = planes->plane[3];
01440             }
01441             if ( tw->sphere.use ) {
01442                 // adjust the plane distance apropriately for radius
01443                 plane[3] += tw->sphere.radius;
01444 
01445                 // find the closest point on the capsule to the plane
01446                 t = DotProduct( plane, tw->sphere.offset );
01447                 if ( t > 0.0f ) {
01448                     VectorSubtract( tw->start, tw->sphere.offset, startp );
01449                     VectorSubtract( tw->end, tw->sphere.offset, endp );
01450                 }
01451                 else {
01452                     VectorAdd( tw->start, tw->sphere.offset, startp );
01453                     VectorAdd( tw->end, tw->sphere.offset, endp );
01454                 }
01455             }
01456             else {
01457                 // NOTE: this works even though the plane might be flipped because the bbox is centered
01458                 offset = DotProduct( tw->offsets[ planes->signbits ], plane);
01459                 plane[3] += fabs(offset);
01460                 VectorCopy( tw->start, startp );
01461                 VectorCopy( tw->end, endp );
01462             }
01463 
01464             if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
01465                 break;
01466             }
01467             if (hit) {
01468                 hitnum = j;
01469                 Vector4Copy(plane, bestplane);
01470             }
01471         }
01472         if (j < facet->numBorders) continue;
01473         //never clip against the back side
01474         if (hitnum == facet->numBorders - 1) continue;
01475 
01476         if (enterFrac < leaveFrac && enterFrac >= 0) {
01477             if (enterFrac < tw->trace.fraction) {
01478                 if (enterFrac < 0) {
01479                     enterFrac = 0;
01480                 }
01481 #ifndef BSPC
01482                 if (!cv) {
01483                     cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
01484                 }
01485                 if (cv && cv->integer) {
01486                     debugPatchCollide = pc;
01487                     debugFacet = facet;
01488                 }
01489 #endif //BSPC
01490 
01491                 tw->trace.fraction = enterFrac;
01492                 VectorCopy( bestplane, tw->trace.plane.normal );
01493                 tw->trace.plane.dist = bestplane[3];
01494             }
01495         }
01496     }
01497 }
01498 
01499 
01500 /*
01501 =======================================================================
01502 
01503 POSITION TEST
01504 
01505 =======================================================================
01506 */
01507 
01508 /*
01509 ====================
01510 CM_PositionTestInPatchCollide
01511 ====================
01512 */
01513 qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
01514     int i, j;
01515     float offset, t;
01516     patchPlane_t *planes;
01517     facet_t *facet;
01518     float plane[4];
01519     vec3_t startp;
01520 
01521     if (tw->isPoint) {
01522         return qfalse;
01523     }
01524     //
01525     facet = pc->facets;
01526     for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
01527         planes = &pc->planes[ facet->surfacePlane ];
01528         VectorCopy(planes->plane, plane);
01529         plane[3] = planes->plane[3];
01530         if ( tw->sphere.use ) {
01531             // adjust the plane distance apropriately for radius
01532             plane[3] += tw->sphere.radius;
01533 
01534             // find the closest point on the capsule to the plane
01535             t = DotProduct( plane, tw->sphere.offset );
01536             if ( t > 0 ) {
01537                 VectorSubtract( tw->start, tw->sphere.offset, startp );
01538             }
01539             else {
01540                 VectorAdd( tw->start, tw->sphere.offset, startp );
01541             }
01542         }
01543         else {
01544             offset = DotProduct( tw->offsets[ planes->signbits ], plane);
01545             plane[3] -= offset;
01546             VectorCopy( tw->start, startp );
01547         }
01548 
01549         if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
01550             continue;
01551         }
01552 
01553         for ( j = 0; j < facet->numBorders; j++ ) {
01554             planes = &pc->planes[ facet->borderPlanes[j] ];
01555             if (facet->borderInward[j]) {
01556                 VectorNegate(planes->plane, plane);
01557                 plane[3] = -planes->plane[3];
01558             }
01559             else {
01560                 VectorCopy(planes->plane, plane);
01561                 plane[3] = planes->plane[3];
01562             }
01563             if ( tw->sphere.use ) {
01564                 // adjust the plane distance apropriately for radius
01565                 plane[3] += tw->sphere.radius;
01566 
01567                 // find the closest point on the capsule to the plane
01568                 t = DotProduct( plane, tw->sphere.offset );
01569                 if ( t > 0.0f ) {
01570                     VectorSubtract( tw->start, tw->sphere.offset, startp );
01571                 }
01572                 else {
01573                     VectorAdd( tw->start, tw->sphere.offset, startp );
01574                 }
01575             }
01576             else {
01577                 // NOTE: this works even though the plane might be flipped because the bbox is centered
01578                 offset = DotProduct( tw->offsets[ planes->signbits ], plane);
01579                 plane[3] += fabs(offset);
01580                 VectorCopy( tw->start, startp );
01581             }
01582 
01583             if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
01584                 break;
01585             }
01586         }
01587         if (j < facet->numBorders) {
01588             continue;
01589         }
01590         // inside this patch facet
01591         return qtrue;
01592     }
01593     return qfalse;
01594 }
01595 
01596 /*
01597 =======================================================================
01598 
01599 DEBUGGING
01600 
01601 =======================================================================
01602 */
01603 
01604 
01605 /*
01606 ==================
01607 CM_DrawDebugSurface
01608 
01609 Called from the renderer
01610 ==================
01611 */
01612 #ifndef BSPC
01613 void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value);
01614 #endif
01615 
01616 void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) {
01617     static cvar_t   *cv;
01618 #ifndef BSPC
01619     static cvar_t   *cv2;
01620 #endif
01621     const patchCollide_t    *pc;
01622     facet_t         *facet;
01623     winding_t       *w;
01624     int             i, j, k, n;
01625     int             curplanenum, planenum, curinward, inward;
01626     float           plane[4];
01627     vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28};
01628     //vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0};
01629     vec3_t v1, v2;
01630 
01631 #ifndef BSPC
01632     if ( !cv2 )
01633     {
01634         cv2 = Cvar_Get( "r_debugSurface", "0", 0 );
01635     }
01636 
01637     if (cv2->integer != 1)
01638     {
01639         BotDrawDebugPolygons(drawPoly, cv2->integer);
01640         return;
01641     }
01642 #endif
01643 
01644     if ( !debugPatchCollide ) {
01645         return;
01646     }
01647 
01648 #ifndef BSPC
01649     if ( !cv ) {
01650         cv = Cvar_Get( "cm_debugSize", "2", 0 );
01651     }
01652 #endif
01653     pc = debugPatchCollide;
01654 
01655     for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) {
01656 
01657         for ( k = 0 ; k < facet->numBorders + 1; k++ ) {
01658             //
01659             if (k < facet->numBorders) {
01660                 planenum = facet->borderPlanes[k];
01661                 inward = facet->borderInward[k];
01662             }
01663             else {
01664                 planenum = facet->surfacePlane;
01665                 inward = qfalse;
01666                 //continue;
01667             }
01668 
01669             Vector4Copy( pc->planes[ planenum ].plane, plane );
01670 
01671             //planenum = facet->surfacePlane;
01672             if ( inward ) {
01673                 VectorSubtract( vec3_origin, plane, plane );
01674                 plane[3] = -plane[3];
01675             }
01676 
01677             plane[3] += cv->value;
01678             //*
01679             for (n = 0; n < 3; n++)
01680             {
01681                 if (plane[n] > 0) v1[n] = maxs[n];
01682                 else v1[n] = mins[n];
01683             } //end for
01684             VectorNegate(plane, v2);
01685             plane[3] += fabs(DotProduct(v1, v2));
01686             //*/
01687 
01688             w = BaseWindingForPlane( plane,  plane[3] );
01689             for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) {
01690                 //
01691                 if (j < facet->numBorders) {
01692                     curplanenum = facet->borderPlanes[j];
01693                     curinward = facet->borderInward[j];
01694                 }
01695                 else {
01696                     curplanenum = facet->surfacePlane;
01697                     curinward = qfalse;
01698                     //continue;
01699                 }
01700                 //
01701                 if (curplanenum == planenum) continue;
01702 
01703                 Vector4Copy( pc->planes[ curplanenum ].plane, plane );
01704                 if ( !curinward ) {
01705                     VectorSubtract( vec3_origin, plane, plane );
01706                     plane[3] = -plane[3];
01707                 }
01708         //          if ( !facet->borderNoAdjust[j] ) {
01709                     plane[3] -= cv->value;
01710         //          }
01711                 for (n = 0; n < 3; n++)
01712                 {
01713                     if (plane[n] > 0) v1[n] = maxs[n];
01714                     else v1[n] = mins[n];
01715                 } //end for
01716                 VectorNegate(plane, v2);
01717                 plane[3] -= fabs(DotProduct(v1, v2));
01718 
01719                 ChopWindingInPlace( &w, plane, plane[3], 0.1f );
01720             }
01721             if ( w ) {
01722                 if ( facet == debugFacet ) {
01723                     drawPoly( 4, w->numpoints, w->p[0] );
01724                     //Com_Printf("blue facet has %d border planes\n", facet->numBorders);
01725                 } else {
01726                     drawPoly( 1, w->numpoints, w->p[0] );
01727                 }
01728                 FreeWinding( w );
01729             }
01730             else
01731                 Com_Printf("winding chopped away by border planes\n");
01732         }
01733     }
01734 
01735     // draw the debug block
01736     {
01737         vec3_t          v[3];
01738 
01739         VectorCopy( debugBlockPoints[0], v[0] );
01740         VectorCopy( debugBlockPoints[1], v[1] );
01741         VectorCopy( debugBlockPoints[2], v[2] );
01742         drawPoly( 2, 3, v[0] );
01743 
01744         VectorCopy( debugBlockPoints[2], v[0] );
01745         VectorCopy( debugBlockPoints[3], v[1] );
01746         VectorCopy( debugBlockPoints[0], v[2] );
01747         drawPoly( 2, 3, v[0] );
01748     }
01749 
01750 #if 0
01751     vec3_t          v[4];
01752 
01753     v[0][0] = pc->bounds[1][0];
01754     v[0][1] = pc->bounds[1][1];
01755     v[0][2] = pc->bounds[1][2];
01756 
01757     v[1][0] = pc->bounds[1][0];
01758     v[1][1] = pc->bounds[0][1];
01759     v[1][2] = pc->bounds[1][2];
01760 
01761     v[2][0] = pc->bounds[0][0];
01762     v[2][1] = pc->bounds[0][1];
01763     v[2][2] = pc->bounds[1][2];
01764 
01765     v[3][0] = pc->bounds[0][0];
01766     v[3][1] = pc->bounds[1][1];
01767     v[3][2] = pc->bounds[1][2];
01768 
01769     drawPoly( 4, v[0] );
01770 #endif
01771 }

Generated on Thu Aug 25 12:37:46 2005 for Quake III Arena by  doxygen 1.3.9.1