void CM_TraceThroughTerrain( traceWork_t *tw, trace_t &trace, cbrush_t *brush ) { CCMLandScape *landscape; vec3_t tBegin, tEnd, tDistance, tStep; vec3_t baseStart; vec3_t baseEnd; int count; int i; float fraction; // At this point we know we may be colliding with a terrain brush (and we know we have a valid terrain structure) landscape = cmg.landScape; if (!landscape) { assert(landscape); Com_Error(ERR_FATAL,"Brush had surfaceparm terrain, but there is no Terrain entity on this map!"); } // Check for absolutely no connection if(!CM_GenericBoxCollide(tw->bounds, landscape->GetBounds())) { return; } // Now we know that at least some part of the trace needs to collide with the terrain // The regular brush collision is handled elsewhere, so advance the ray to an edge in the terrain brush CM_TraceThroughBrush( tw, trace, brush, true ); // Remember the base entering and leaving fractions tw->baseEnterFrac = tw->enterFrac; tw->baseLeaveFrac = tw->leaveFrac; // Reset to full spread within the brush tw->enterFrac = -1.0f; tw->leaveFrac = 1.0f; // Work out the corners of the AABB when the trace first hits the terrain brush and when it leaves VectorAdvance(tw->start, tw->baseEnterFrac, tw->end, tBegin); VectorAdvance(tw->start, tw->baseLeaveFrac, tw->end, tEnd); VectorSubtract(tEnd, tBegin, tDistance); // Calculate number of iterations to process count = ceilf(VectorLength(tDistance) / (landscape->GetPatchScalarSize() * TERRAIN_STEP_MAGIC)); count = 1; fraction = trace.fraction; VectorScale(tDistance, 1.0f / count, tStep); // Save the base start and end vectors VectorCopy ( tw->start, baseStart ); VectorCopy ( tw->end, baseEnd ); // Use the terrain vectors. Start both at the beginning since the // step will be added to the end as the first step of the loop VectorCopy ( tBegin, tw->start ); VectorCopy ( tBegin, tw->end ); // Step thru terrain patches moving on about 1 patch at a time for ( i = 0; i < count; i ++ ) { // Add the step to the end VectorAdd(tw->end, tStep, tw->end); CM_CalcExtents(tBegin, tw->end, tw, tw->localBounds); landscape->PatchCollide(tw, trace, tw->start, tw->end, brush->checkcount); // If collision with something closer than water then just stop here if ( trace.fraction < fraction ) { // Convert the fraction of this sub tract into the full trace's fraction trace.fraction = i * (1.0f / count) + (1.0f / count) * trace.fraction; break; } // Move the end to the start so the next trace starts // where this one left off VectorCopy(tw->end, tw->start); } // Put the original start and end back VectorCopy ( baseStart, tw->start ); VectorCopy ( baseEnd, tw->end ); // Convert to global fraction only if something was hit along the way if ( trace.fraction != 1.0 ) { trace.fraction = tw->baseEnterFrac + ((tw->baseLeaveFrac - tw->baseEnterFrac) * trace.fraction); trace.contents = brush->contents; } // Collide with any water if ( tw->contents & CONTENTS_WATER ) { fraction = landscape->WaterCollide(tw->start, tw->end, trace.fraction); if( fraction < trace.fraction ) { VectorSet(trace.plane.normal, 0.0f, 0.0f, 1.0f); trace.contents = landscape->GetWaterContents(); trace.fraction = fraction; trace.surfaceFlags = landscape->GetWaterSurfaceFlags(); } } }
void CM_TraceThroughTerrain( traceWork_t *tw, trace_t &trace, CCMLandScape *landscape) { vec3_t tBegin, tEnd, tDistance, tStep; vec3_t baseStart; vec3_t baseEnd; int count; int i; float fraction; // Check for absolutely no connection if(!CM_GenericBoxCollide(tw->bounds, landscape->GetBounds())) { return; } tw->enterFrac = 0.0f; tw->leaveFrac = 1.0f; tw->clipplane = NULL; tw->getout = false; tw->startout = false; tw->leadside = NULL; // Remember the base entering and leaving fractions tw->baseEnterFrac = tw->enterFrac; tw->baseLeaveFrac = tw->leaveFrac; // Reset to full spread within the brush tw->enterFrac = -1.0f; tw->leaveFrac = 1.0f; // Work out the corners of the AABB when the trace first hits the terrain brush and when it leaves VectorAdvance(tw->start, tw->baseEnterFrac, tw->end, tBegin); VectorAdvance(tw->start, tw->baseLeaveFrac, tw->end, tEnd); VectorSubtract(tEnd, tBegin, tDistance); // Calculate number of iterations to process count = ceilf(VectorLength(tDistance) / (landscape->GetPatchScalarSize() * TERRAIN_STEP_MAGIC)); count = 1; fraction = trace.fraction; VectorScale(tDistance, 1.0f / count, tStep); // Save the base start and end vectors VectorCopy ( tw->start, baseStart ); VectorCopy ( tw->end, baseEnd ); // Use the terrain vectors. Start both at the beginning since the // step will be added to the end as the first step of the loop VectorCopy ( tBegin, tw->start ); VectorCopy ( tBegin, tw->end ); // Step thru terrain patches moving on about 1 patch at a time for ( i = 0; i < count; i ++ ) { // Add the step to the end VectorAdd(tw->end, tStep, tw->end); CM_CalcExtents(tBegin, tw->end, tw, tw->localBounds); landscape->PatchCollide(tw, trace, tw->start, tw->end, cmg.checkcount); // If collision with something closer than water then just stop here if ( trace.fraction < fraction ) { // Convert the fraction of this sub tract into the full trace's fraction trace.fraction = i * (1.0f / count) + (1.0f / count) * trace.fraction; break; } // Move the end to the start so the next trace starts // where this one left off VectorCopy(tw->end, tw->start); } // Put the original start and end back VectorCopy ( baseStart, tw->start ); VectorCopy ( baseEnd, tw->end ); // Convert to global fraction only if something was hit along the way if ( trace.fraction != 1.0 ) { // trace.fraction = tw->baseEnterFrac + ((tw->baseLeaveFrac - tw->baseEnterFrac) * trace.fraction); trace.contents = CONTENTS_TERRAIN | CONTENTS_OUTSIDE; } // Collide with any water if ( tw->contents & CONTENTS_WATER ) { fraction = landscape->WaterCollide(tw->start, tw->end, trace.fraction); if( fraction < trace.fraction ) { VectorSet(trace.plane.normal, 0.0f, 0.0f, 1.0f); trace.contents = landscape->GetWaterContents(); trace.fraction = fraction; trace.surfaceFlags = landscape->GetWaterSurfaceFlags(); } } }