/* ==================== CM_TraceThroughPatchCollide ==================== */ void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) { int i, j, hit, hitnum; float offset, enterFrac, leaveFrac, t; patchPlane_t *planes; facet_t *facet; float plane[4] = {0, 0, 0, 0}, bestplane[4] = {0, 0, 0, 0}; vec3_t startp, endp; #ifndef BSPC static cvar_t *cv; #endif if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1], pc->bounds[0], pc->bounds[1] ) ) { return; } if ( tw->isPoint ) { CM_TracePointThroughPatchCollide( tw, pc ); return; } #ifndef ADDBEVELS CM_TracePointThroughPatchCollide( tw, pc ); return; #endif // facet = pc->facets; for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) { enterFrac = -1.0; leaveFrac = 1.0; hitnum = -1; // planes = &pc->planes[ facet->surfacePlane ]; VectorCopy( planes->plane, plane ); plane[3] = planes->plane[3]; if ( tw->sphere.use ) { // adjust the plane distance apropriately for radius plane[3] += tw->sphere.radius; // find the closest point on the capsule to the plane t = DotProduct( plane, tw->sphere.offset ); if ( t > 0 ) { VectorSubtract( tw->start, tw->sphere.offset, startp ); VectorSubtract( tw->end, tw->sphere.offset, endp ); } else { VectorAdd( tw->start, tw->sphere.offset, startp ); VectorAdd( tw->end, tw->sphere.offset, endp ); } } else { offset = DotProduct( tw->offsets[ planes->signbits ], plane ); plane[3] -= offset; VectorCopy( tw->start, startp ); VectorCopy( tw->end, endp ); } // if ( !CM_CheckFacetPlane( plane, startp, endp, &enterFrac, &leaveFrac, &hit ) ) { continue; } if ( hit ) { Vector4Copy( plane, bestplane ); } // for ( j = 0 ; j < facet->numBorders ; j++ ) { planes = &pc->planes[ facet->borderPlanes[j] ]; if ( facet->borderInward[j] ) { VectorNegate( planes->plane, plane ); plane[3] = -planes->plane[3]; } else { VectorCopy( planes->plane, plane ); plane[3] = planes->plane[3]; } if ( tw->sphere.use ) { // adjust the plane distance apropriately for radius plane[3] += tw->sphere.radius; // find the closest point on the capsule to the plane t = DotProduct( plane, tw->sphere.offset ); if ( t > 0 ) { VectorSubtract( tw->start, tw->sphere.offset, startp ); VectorSubtract( tw->end, tw->sphere.offset, endp ); } else { VectorAdd( tw->start, tw->sphere.offset, startp ); VectorAdd( tw->end, tw->sphere.offset, endp ); } } else { // NOTE: this works even though the plane might be flipped because the bbox is centered offset = DotProduct( tw->offsets[ planes->signbits ], plane ); plane[3] += fabs( offset ); VectorCopy( tw->start, startp ); VectorCopy( tw->end, endp ); } // if ( !CM_CheckFacetPlane( plane, startp, endp, &enterFrac, &leaveFrac, &hit ) ) { break; } if ( hit ) { hitnum = j; Vector4Copy( plane, bestplane ); } } if ( j < facet->numBorders ) { continue; } //never clip against the back side if ( hitnum == facet->numBorders - 1 ) { continue; } // if ( enterFrac < leaveFrac && enterFrac >= 0 ) { if ( enterFrac < tw->trace.fraction ) { if ( enterFrac < 0 ) { enterFrac = 0; } #ifndef BSPC if ( !cv ) { cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 ); } if ( cv && cv->integer ) { debugPatchCollide = pc; debugFacet = facet; } #endif tw->trace.fraction = enterFrac; VectorCopy( bestplane, tw->trace.plane.normal ); tw->trace.plane.dist = bestplane[3]; } } } }
static void CM_TraceThroughLeaf( traceWork_t* tw, const cLeaf_t* leaf ) { int k; int brushnum; cbrush_t *b; cPatch_t *patch; // trace line against all brushes in the leaf for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) { brushnum = cm.leafbrushes[leaf->firstLeafBrush+k]; b = &cm.brushes[brushnum]; if ( b->checkcount == cm.checkcount ) { continue; // already checked this brush in another leaf } b->checkcount = cm.checkcount; if ( !(b->contents & tw->contents) ) { continue; } if (!CM_BoundsIntersect( tw->bounds[0], tw->bounds[1], b->bounds[0], b->bounds[1] )) continue; CM_TraceThroughBrush( tw, b ); if ( !tw->trace.fraction ) { return; } } // trace line against all patches in the leaf #ifdef BSPC if (1) { #else if ( !cm_noCurves->integer ) { #endif for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) { patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ]; if ( !patch ) { continue; } if ( patch->checkcount == cm.checkcount ) { continue; // already checked this patch in another leaf } patch->checkcount = cm.checkcount; if ( !(patch->contents & tw->contents) ) { continue; } CM_TraceThroughPatch( tw, patch ); if ( !tw->trace.fraction ) { return; } } } } #define RADIUS_EPSILON 1.0f /* ================ CM_TraceThroughSphere get the first intersection of the ray with the sphere ================ */ void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) { float l1, l2, length, scale, fraction; float a, b, c, d, sqrtd; vec3_t v1, dir, intersection; // if inside the sphere VectorSubtract(start, origin, dir); l1 = VectorLengthSquared(dir); if (l1 < Square(radius)) { tw->trace.fraction = 0; tw->trace.startsolid = qtrue; // test for allsolid VectorSubtract(end, origin, dir); l1 = VectorLengthSquared(dir); if (l1 < Square(radius)) { tw->trace.allsolid = qtrue; } return; } // VectorSubtract(end, start, dir); length = VectorNormalize(dir); // l1 = CM_DistanceFromLineSquared(origin, start, end, dir); VectorSubtract(end, origin, v1); l2 = VectorLengthSquared(v1); // if no intersection with the sphere and the end point is at least an epsilon away if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) { return; } // // | origin - (start + t * dir) | = radius // a = dir[0]^2 + dir[1]^2 + dir[2]^2; // b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2])); // c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2; // VectorSubtract(start, origin, v1); // dir is normalized so a = 1 a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]; b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]); c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON); d = b * b - 4.0f * c;// * a; if (d > 0) { sqrtd = SquareRootFloat(d); // = (- b + sqrtd) * 0.5f; // / (2.0f * a); fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a); // if (fraction < 0) { fraction = 0; } else { fraction /= length; } if ( fraction < tw->trace.fraction ) { tw->trace.fraction = fraction; VectorSubtract(end, start, dir); VectorMA(start, fraction, dir, intersection); VectorSubtract(intersection, origin, dir); #ifdef CAPSULE_DEBUG l2 = VectorLength(dir); if (l2 < radius) { int bah = 1; } #endif scale = 1 / (radius+RADIUS_EPSILON); VectorScale(dir, scale, dir); VectorCopy(dir, tw->trace.plane.normal); VectorAdd( tw->modelOrigin, intersection, intersection); tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection); tw->trace.contents = CONTENTS_BODY; } } else if (d == 0) { //t1 = (- b ) / 2; // slide along the sphere } // no intersection at all }