/* ============ idClip::Translation ============ */ bool idClip::Translation( trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { int i, num; idClipModel *touch, *clipModelList[MAX_GENTITIES]; idBounds traceBounds; float radius; trace_t trace; const idTraceModel *trm; if( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) { return true; } trm = TraceModelForClipModel( mdl ); if( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { // test world idClip::numTranslations++; collisionModelManager->Translation( &results, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); results.c.entityNum = results.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; if( results.fraction == 0.0f ) { return true; // blocked immediately by the world } } else { memset( &results, 0, sizeof( results ) ); results.fraction = 1.0f; results.endpos = end; results.endAxis = trmAxis; } if( !trm ) { traceBounds.FromPointTranslation( start, results.endpos - start ); radius = 0.0f; } else { traceBounds.FromBoundsTranslation( trm->bounds, start, trmAxis, results.endpos - start ); radius = trm->bounds.GetRadius(); } num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); for( i = 0; i < num; i++ ) { touch = clipModelList[i]; if( !touch ) { continue; } if( touch->renderModelHandle != -1 ) { idClip::numRenderModelTraces++; TraceRenderModel( trace, start, end, radius, trmAxis, touch ); } else { idClip::numTranslations++; collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ); } if( trace.fraction < results.fraction ) { results = trace; results.c.entityNum = touch->entity->entityNumber; results.c.id = touch->id; if( results.fraction == 0.0f ) { break; } } } return ( results.fraction < 1.0f ); }
/* ============ idClip::TranslationEntities ============ */ void idClip::TranslationEntities( trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { int i, num; idClipModel *touch, *clipModelList[MAX_GENTITIES]; idBounds traceBounds; float radius; trace_t trace; const idTraceModel *trm; if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) { return; } trm = TraceModelForClipModel( mdl ); results.fraction = 1.0f; results.endpos = end; results.endAxis = trmAxis; if ( !trm ) { traceBounds.FromPointTranslation( start, end - start ); radius = 0.0f; } else { traceBounds.FromBoundsTranslation( trm->bounds, start, trmAxis, end - start ); radius = trm->bounds.GetRadius(); } num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); for ( i = 0; i < num; i++ ) { touch = clipModelList[i]; if ( !touch ) { continue; } if ( touch->renderModelHandle != -1 ) { idClip::numRenderModelTraces++; TraceRenderModel( trace, start, end, radius, trmAxis, touch ); } else { idClip::numTranslations++; collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ); } if ( trace.fraction < results.fraction ) { results = trace; results.c.entityNum = touch->entity->entityNumber; results.c.id = touch->id; if ( results.fraction == 0.0f ) { break; } } } }
/* ============ idClip::Motion ============ */ bool idClip::Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { int i, num; idClipModel *touch, *clipModelList[MAX_GENTITIES]; idVec3 dir, endPosition; idBounds traceBounds; float radius; trace_t translationalTrace, rotationalTrace, trace; idRotation endRotation; const idTraceModel *trm; assert( rotation.GetOrigin() == start ); if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) { return true; } if ( mdl != NULL && rotation.GetAngle() != 0.0f && rotation.GetVec() != vec3_origin ) { // if no translation if ( start == end ) { // pure rotation return Rotation( results, start, rotation, mdl, trmAxis, contentMask, passEntity ); } } else if ( start != end ) { // pure translation return Translation( results, start, end, mdl, trmAxis, contentMask, passEntity ); } else { // no motion results.fraction = 1.0f; results.endpos = start; results.endAxis = trmAxis; return false; } trm = TraceModelForClipModel( mdl ); radius = trm->bounds.GetRadius(); if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { // translational collision with world idClip::numTranslations++; collisionModelManager->Translation( &translationalTrace, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); translationalTrace.c.entityNum = translationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; } else { memset( &translationalTrace, 0, sizeof( translationalTrace ) ); translationalTrace.fraction = 1.0f; translationalTrace.endpos = end; translationalTrace.endAxis = trmAxis; } if ( translationalTrace.fraction != 0.0f ) { traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation ); dir = translationalTrace.endpos - start; for ( i = 0; i < 3; i++ ) { if ( dir[i] < 0.0f ) { traceBounds[0][i] += dir[i]; } else { traceBounds[1][i] += dir[i]; } } num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); for ( i = 0; i < num; i++ ) { touch = clipModelList[i]; if ( !touch ) { continue; } if ( touch->renderModelHandle != -1 ) { idClip::numRenderModelTraces++; TraceRenderModel( trace, start, end, radius, trmAxis, touch ); } else { idClip::numTranslations++; collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ); } if ( trace.fraction < translationalTrace.fraction ) { translationalTrace = trace; translationalTrace.c.entityNum = touch->entity->entityNumber; translationalTrace.c.id = touch->id; if ( translationalTrace.fraction == 0.0f ) { break; } } } } else { num = -1; } endPosition = translationalTrace.endpos; endRotation = rotation; endRotation.SetOrigin( endPosition ); if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { // rotational collision with world idClip::numRotations++; collisionModelManager->Rotation( &rotationalTrace, endPosition, endRotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); rotationalTrace.c.entityNum = rotationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; } else { memset( &rotationalTrace, 0, sizeof( rotationalTrace ) ); rotationalTrace.fraction = 1.0f; rotationalTrace.endpos = endPosition; rotationalTrace.endAxis = trmAxis * rotation.ToMat3(); } if ( rotationalTrace.fraction != 0.0f ) { if ( num == -1 ) { traceBounds.FromBoundsRotation( trm->bounds, endPosition, trmAxis, endRotation ); num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); } for ( i = 0; i < num; i++ ) { touch = clipModelList[i]; if ( !touch ) { continue; } // no rotational collision detection with render models if ( touch->renderModelHandle != -1 ) { continue; } idClip::numRotations++; collisionModelManager->Rotation( &trace, endPosition, endRotation, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ); if ( trace.fraction < rotationalTrace.fraction ) { rotationalTrace = trace; rotationalTrace.c.entityNum = touch->entity->entityNumber; rotationalTrace.c.id = touch->id; if ( rotationalTrace.fraction == 0.0f ) { break; } } } } if ( rotationalTrace.fraction < 1.0f ) { results = rotationalTrace; } else { results = translationalTrace; results.endAxis = rotationalTrace.endAxis; } results.fraction = Max( translationalTrace.fraction, rotationalTrace.fraction ); return ( translationalTrace.fraction < 1.0f || rotationalTrace.fraction < 1.0f ); }