void SV_ClearWorld( void ) { clipHandle_t h; vector3 mins, maxs; memset( sv_worldSectors, 0, sizeof(sv_worldSectors) ); sv_numworldSectors = 0; // get world map bounds h = CM_InlineModel( 0 ); CM_ModelBounds( h, &mins, &maxs ); SV_CreateworldSector( 0, &mins, &maxs ); }
// capsule vs. capsule collision (not rotated) void CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) { int i; vector3 mins, maxs; vector3 top, bottom, starttop, startbottom, endtop, endbottom; vector3 offset, symetricSize[2]; float radius, halfwidth, halfheight, offs, h; CM_ModelBounds(model, &mins, &maxs); // test trace bounds vs. capsule bounds if ( tw->bounds[0].x > maxs.x + RADIUS_EPSILON || tw->bounds[0].y > maxs.y + RADIUS_EPSILON || tw->bounds[0].z > maxs.z + RADIUS_EPSILON || tw->bounds[1].x < mins.x - RADIUS_EPSILON || tw->bounds[1].y < mins.y - RADIUS_EPSILON || tw->bounds[1].z < mins.z - RADIUS_EPSILON) { return; } // top origin and bottom origin of each sphere at start and end of trace VectorAdd(&tw->start, &tw->sphere.offset, &starttop); VectorSubtract(&tw->start, &tw->sphere.offset, &startbottom); VectorAdd(&tw->end, &tw->sphere.offset, &endtop); VectorSubtract(&tw->end, &tw->sphere.offset, &endbottom); // calculate top and bottom of the capsule spheres to collide with for ( i = 0 ; i < 3 ; i++ ) { offset.data[i] = ( mins.data[i] + maxs.data[i] ) * 0.5f; symetricSize[0].data[i] = mins.data[i] - offset.data[i]; symetricSize[1].data[i] = maxs.data[i] - offset.data[i]; } halfwidth = symetricSize[1].x; halfheight = symetricSize[1].z; radius = ( halfwidth > halfheight ) ? halfheight : halfwidth; offs = halfheight - radius; VectorCopy(&offset, &top); top.z += offs; VectorCopy(&offset, &bottom); bottom.z -= offs; // expand radius of spheres radius += tw->sphere.radius; // if there is horizontal movement if ( tw->start.x != tw->end.x || tw->start.y != tw->end.y ) { // height of the expanded cylinder is the height of both cylinders minus the radius of both spheres h = halfheight + tw->sphere.halfheight - radius; // if the cylinder has a height if ( h > 0 ) { // test for collisions between the cylinders CM_TraceThroughVerticalCylinder(tw, &offset, radius, h, &tw->start, &tw->end); } } // test for collision between the spheres CM_TraceThroughSphere(tw, &top, radius, &startbottom, &endbottom); CM_TraceThroughSphere(tw, &bottom, radius, &starttop, &endtop); }
/* * SV_ClearWorld * */ void SV_ClearWorld(void) { Cliphandle h; Vec3 mins, maxs; Q_Memset(sv_worldSectors, 0, sizeof(sv_worldSectors)); sv_numworldSectors = 0; /* get world map bounds */ h = CM_InlineModel(0); CM_ModelBounds(h, mins, maxs); SV_CreateworldSector(0, mins, maxs); }
/* ================== CM_TestBoundingBoxInCapsule bounding box inside capsule check ================== */ void CM_TestBoundingBoxInCapsule( traceWork_t *tw, clipHandle_t model ) { vec3_t mins, maxs, offset, bboxSize[2]; clipHandle_t h; cmodel_t *cmod; int i; // save size of the bounding box VectorCopy(tw->size[0], bboxSize[0]); VectorCopy(tw->size[1], bboxSize[1]); // mins maxs of the capsule CM_ModelBounds(model, mins, maxs); // offset for capsule center for ( i = 0 ; i < 3 ; i++ ) { offset[i] = ( mins[i] + maxs[i] ) * 0.5; tw->size[0][i] = mins[i] - offset[i]; tw->size[1][i] = maxs[i] - offset[i]; tw->start[i] -= offset[i]; tw->end[i] -= offset[i]; if ( tw->start[i] < tw->end[i] ) { tw->bounds[0][i] = tw->start[i] + tw->size[0][i]; tw->bounds[1][i] = tw->end[i] + tw->size[1][i]; } else { tw->bounds[0][i] = tw->end[i] + tw->size[0][i]; tw->bounds[1][i] = tw->start[i] + tw->size[1][i]; } } // replace the bounding box with the capsule tw->type = TT_CAPSULE; tw->sphere.radius = ( tw->size[1][0] > tw->size[1][2] ) ? tw->size[1][2]: tw->size[1][0]; tw->sphere.halfheight = tw->size[1][2]; VectorSet( tw->sphere.offset, 0, 0, tw->size[1][2] - tw->sphere.radius ); // replace the capsule with the bounding box h = CM_TempBoxModel(bboxSize[0], bboxSize[1], qfalse, capsule_contents); // calculate collision cmod = CM_ClipHandleToModel( h ); CM_TestInLeaf( tw, &cmod->leaf ); }
/* ================== BotImport_BSPModelMinsMaxsOrigin ================== */ static void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) { clipHandle_t h; vec3_t mins, maxs; float max; int i; h = CM_InlineModel(modelnum); CM_ModelBounds(h, mins, maxs); //if the model is rotated if ((angles[0] || angles[1] || angles[2])) { // expand for rotation max = RadiusFromBounds(mins, maxs); for (i = 0; i < 3; i++) { mins[i] = -max; maxs[i] = max; } } if (outmins) VectorCopy(mins, outmins); if (outmaxs) VectorCopy(maxs, outmaxs); if (origin) VectorClear(origin); }
static void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vector3 *angles, vector3 *outmins, vector3 *outmaxs, vector3 *origin) { clipHandle_t h; vector3 mins, maxs; float max; int i; h = CM_InlineModel(modelnum); CM_ModelBounds(h, &mins, &maxs); //if the model is rotated if ((angles->pitch || angles->yaw || angles->roll)) { // expand for rotation max = RadiusFromBounds(&mins, &maxs); for (i = 0; i < 3; i++) { mins.data[i] = -max; maxs.data[i] = max; } } if (outmins) VectorCopy(&mins, outmins); if (outmaxs) VectorCopy(&maxs, outmaxs); if (origin) VectorClear(origin); }
/* ================= SV_SetBrushModel sets mins and maxs for inline bmodels ================= */ void SV_SetBrushModel(sharedEntity_t * ent, const char *name) { clipHandle_t h; vec3_t mins, maxs; if(!name) { Com_Error(ERR_DROP, "SV_SetBrushModel: NULL"); } if(name[0] != '*') { Com_Error(ERR_DROP, "SV_SetBrushModel: %s isn't a brush model", name); } ent->s.modelindex = atoi(name + 1); h = CM_InlineModel(ent->s.modelindex); CM_ModelBounds(h, mins, maxs); VectorCopy(mins, ent->r.mins); VectorCopy(maxs, ent->r.maxs); ent->r.bmodel = true; ent->r.contents = -1; // we don't know exactly what is in the brushes SV_LinkEntity(ent); // FIXME: remove }
/* ================== CM_TestCapsuleInCapsule capsule inside capsule check ================== */ void CM_TestCapsuleInCapsule(traceWork_t *tw, clipHandle_t model) { int i; vec3_t mins, maxs; vec3_t top, bottom; vec3_t p1, p2, tmp; vec3_t offset, symetricSize[2]; float radius, halfwidth, halfheight, offs, r; CM_ModelBounds(model, mins, maxs); VectorAdd(tw->start, tw->sphere.offset, top); VectorSubtract(tw->start, tw->sphere.offset, bottom); for (i = 0 ; i < 3 ; i++) { offset[i] = (mins[i] + maxs[i]) * 0.5; symetricSize[0][i] = mins[i] - offset[i]; symetricSize[1][i] = maxs[i] - offset[i]; } halfwidth = symetricSize[1][0]; halfheight = symetricSize[1][2]; radius = (halfwidth > halfheight) ? halfheight : halfwidth; offs = halfheight - radius; r = Square(tw->sphere.radius + radius); // check if any of the spheres overlap VectorCopy(offset, p1); p1[2] += offs; VectorSubtract(p1, top, tmp); if (VectorLengthSquared(tmp) < r) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } VectorSubtract(p1, bottom, tmp); if (VectorLengthSquared(tmp) < r) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } VectorCopy(offset, p2); p2[2] -= offs; VectorSubtract(p2, top, tmp); if (VectorLengthSquared(tmp) < r) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } VectorSubtract(p2, bottom, tmp); if (VectorLengthSquared(tmp) < r) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } // if between cylinder up and lower bounds if ((top[2] >= p1[2] && top[2] <= p2[2]) || (bottom[2] >= p1[2] && bottom[2] <= p2[2])) { // 2d coordinates top[2] = p1[2] = 0; // if the cylinders overlap VectorSubtract(top, p1, tmp); if (VectorLengthSquared(tmp) < r) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } } }
static void CM_TestInLeaf( traceWork_t* tw, const cLeaf_t* leaf ) { int k; int brushnum; cbrush_t *b; cPatch_t *patch; // test box position 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; } CM_TestBoxInBrush( tw, b ); if ( tw->trace.allsolid ) { return; } } // test against all patches #ifdef BSPC if (1) { #else if ( !cm_noCurves->integer ) { #endif //BSPC 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 brush in another leaf } patch->checkcount = cm.checkcount; if ( !(patch->contents & tw->contents)) { continue; } if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; tw->trace.contents = patch->contents; return; } } } } /* ================== CM_TestCapsuleInCapsule capsule inside capsule check ================== */ void CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) { int i; vec3_t mins, maxs; vec3_t top, bottom; vec3_t p1, p2, tmp; vec3_t offset, symetricSize[2]; float radius, halfwidth, halfheight, offs, r; CM_ModelBounds(model, mins, maxs); VectorAdd(tw->start, tw->sphere.offset, top); VectorSubtract(tw->start, tw->sphere.offset, bottom); for ( i = 0 ; i < 3 ; i++ ) { offset[i] = ( mins[i] + maxs[i] ) * 0.5; symetricSize[0][i] = mins[i] - offset[i]; symetricSize[1][i] = maxs[i] - offset[i]; } halfwidth = symetricSize[ 1 ][ 0 ]; halfheight = symetricSize[ 1 ][ 2 ]; radius = ( halfwidth > halfheight ) ? halfheight : halfwidth; offs = halfheight - radius; r = Square(tw->sphere.radius + radius); // check if any of the spheres overlap VectorCopy(offset, p1); p1[2] += offs; VectorSubtract(p1, top, tmp); if ( VectorLengthSquared(tmp) < r ) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } VectorSubtract(p1, bottom, tmp); if ( VectorLengthSquared(tmp) < r ) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } VectorCopy(offset, p2); p2[2] -= offs; VectorSubtract(p2, top, tmp); if ( VectorLengthSquared(tmp) < r ) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } VectorSubtract(p2, bottom, tmp); if ( VectorLengthSquared(tmp) < r ) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } // if between cylinder up and lower bounds if ( (top[2] >= p1[2] && top[2] <= p2[2]) || (bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) { // 2d coordinates top[2] = p1[2] = 0; // if the cylinders overlap VectorSubtract(top, p1, tmp); if ( VectorLengthSquared(tmp) < r ) { tw->trace.startsolid = tw->trace.allsolid = qtrue; tw->trace.fraction = 0; } } }
/* ================ CM_TraceCapsuleThroughCapsule capsule vs. capsule collision (not rotated) ================ */ void CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) { int i; vec3_t mins, maxs; vec3_t top, bottom, starttop, startbottom, endtop, endbottom; vec3_t offset, symetricSize[2]; float radius, halfwidth, halfheight, offs, h; CM_ModelBounds(model, mins, maxs); // test trace bounds vs. capsule bounds if ( tw->bounds[0][0] > maxs[0] + RADIUS_EPSILON || tw->bounds[0][1] > maxs[1] + RADIUS_EPSILON || tw->bounds[0][2] > maxs[2] + RADIUS_EPSILON || tw->bounds[1][0] < mins[0] - RADIUS_EPSILON || tw->bounds[1][1] < mins[1] - RADIUS_EPSILON || tw->bounds[1][2] < mins[2] - RADIUS_EPSILON ) { return; } // top origin and bottom origin of each sphere at start and end of trace VectorAdd(tw->start, tw->sphere.offset, starttop); VectorSubtract(tw->start, tw->sphere.offset, startbottom); VectorAdd(tw->end, tw->sphere.offset, endtop); VectorSubtract(tw->end, tw->sphere.offset, endbottom); // calculate top and bottom of the capsule spheres to collide with for ( i = 0 ; i < 3 ; i++ ) { offset[i] = ( mins[i] + maxs[i] ) * 0.5; symetricSize[0][i] = mins[i] - offset[i]; symetricSize[1][i] = maxs[i] - offset[i]; } halfwidth = symetricSize[ 1 ][ 0 ]; halfheight = symetricSize[ 1 ][ 2 ]; radius = ( halfwidth > halfheight ) ? halfheight : halfwidth; offs = halfheight - radius; VectorCopy(offset, top); top[2] += offs; VectorCopy(offset, bottom); bottom[2] -= offs; // expand radius of spheres radius += tw->sphere.radius; // if there is horizontal movement if ( tw->start[0] != tw->end[0] || tw->start[1] != tw->end[1] ) { // height of the expanded cylinder is the height of both cylinders minus the radius of both spheres h = halfheight + tw->sphere.halfheight - radius; // if the cylinder has a height if ( h > 0 ) { // test for collisions between the cylinders CM_TraceThroughVerticalCylinder(tw, offset, radius, h, tw->start, tw->end, capsule_contents); if ( tw->trace.allsolid ) { return; } } } // test for collision between the spheres CM_TraceThroughSphere(tw, top, radius, startbottom, endbottom, capsule_contents); if ( tw->trace.allsolid ) { return; } CM_TraceThroughSphere(tw, bottom, radius, starttop, endtop, capsule_contents); }
/* ================ CM_TestInLeaf ================ */ void CM_TestInLeaf( traceWork_t *tw, trace_t &trace, cLeaf_t *leaf, clipMap_t *local ) { int k; int brushnum; cbrush_t *b; cPatch_t *patch; // test box position against all brushes in the leaf for (k=0 ; k<leaf->numLeafBrushes ; k++) { brushnum = local->leafbrushes[leaf->firstLeafBrush+k]; b = &local->brushes[brushnum]; if (b->checkcount == local->checkcount) { continue; // already checked this brush in another leaf } b->checkcount = local->checkcount; if ( !(b->contents & tw->contents)) { continue; } #ifndef BSPC if (com_terrainPhysics->integer && cmg.landScape && (b->contents & CONTENTS_TERRAIN) ) { // Invalidate the checkcount for terrain as the terrain brush has to be processed // many times. b->checkcount--; CM_TraceThroughTerrain( tw, trace, b ); // If inside a terrain brush don't bother with regular brush collision continue; } #endif CM_TestBoxInBrush( tw, trace, b ); if ( trace.allsolid ) { return; } } // test against all patches #ifdef BSPC if (1) { #else if ( !cm_noCurves->integer ) { #endif //BSPC for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) { patch = local->surfaces[ local->leafsurfaces[ leaf->firstLeafSurface + k ] ]; if ( !patch ) { continue; } if ( patch->checkcount == local->checkcount ) { continue; // already checked this brush in another leaf } patch->checkcount = local->checkcount; if ( !(patch->contents & tw->contents)) { continue; } if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) { trace.startsolid = trace.allsolid = qtrue; trace.fraction = 0; trace.contents = patch->contents; return; } } } } /* ================== CM_TestCapsuleInCapsule capsule inside capsule check ================== */ void CM_TestCapsuleInCapsule( traceWork_t *tw, trace_t &trace, clipHandle_t model ) { int i; vec3_t mins, maxs; vec3_t top, bottom; vec3_t p1, p2, tmp; vec3_t offset, symetricSize[2]; float radius, halfwidth, halfheight, offs, r; CM_ModelBounds(model, mins, maxs); VectorAdd(tw->start, tw->sphere.offset, top); VectorSubtract(tw->start, tw->sphere.offset, bottom); for ( i = 0 ; i < 3 ; i++ ) { offset[i] = ( mins[i] + maxs[i] ) * 0.5; symetricSize[0][i] = mins[i] - offset[i]; symetricSize[1][i] = maxs[i] - offset[i]; } halfwidth = symetricSize[ 1 ][ 0 ]; halfheight = symetricSize[ 1 ][ 2 ]; radius = ( halfwidth > halfheight ) ? halfheight : halfwidth; offs = halfheight - radius; r = Square(tw->sphere.radius + radius); // check if any of the spheres overlap VectorCopy(offset, p1); p1[2] += offs; VectorSubtract(p1, top, tmp); if ( VectorLengthSquared(tmp) < r ) { trace.startsolid = trace.allsolid = qtrue; trace.fraction = 0; } VectorSubtract(p1, bottom, tmp); if ( VectorLengthSquared(tmp) < r ) { trace.startsolid = trace.allsolid = qtrue; trace.fraction = 0; } VectorCopy(offset, p2); p2[2] -= offs; VectorSubtract(p2, top, tmp); if ( VectorLengthSquared(tmp) < r ) { trace.startsolid = trace.allsolid = qtrue; trace.fraction = 0; } VectorSubtract(p2, bottom, tmp); if ( VectorLengthSquared(tmp) < r ) { trace.startsolid = trace.allsolid = qtrue; trace.fraction = 0; } // if between cylinder up and lower bounds if ( (top[2] >= p1[2] && top[2] <= p2[2]) || (bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) { // 2d coordinates top[2] = p1[2] = 0; // if the cylinders overlap VectorSubtract(top, p1, tmp); if ( VectorLengthSquared(tmp) < r ) { trace.startsolid = trace.allsolid = qtrue; trace.fraction = 0; } } }