/* ============ idClip::Contents ============ */ int idClip::Contents( const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { int i, num, contents; idClipModel *touch, *clipModelList[MAX_GENTITIES]; idBounds traceBounds; const idTraceModel *trm; trm = TraceModelForClipModel( mdl ); if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { // test world idClip::numContents++; contents = collisionModelManager->Contents( start, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); } else { contents = 0; } if ( !trm ) { traceBounds[0] = start; traceBounds[1] = start; } else if ( trmAxis.IsRotated() ) { traceBounds.FromTransformedBounds( trm->bounds, start, trmAxis ); } else { traceBounds[0] = trm->bounds[0] + start; traceBounds[1] = trm->bounds[1] + start; } num = GetTraceClipModels( traceBounds, -1, passEntity, clipModelList ); for ( i = 0; i < num; i++ ) { touch = clipModelList[i]; if ( !touch ) { continue; } // no contents test with render models if ( touch->renderModelHandle != -1 ) { continue; } // if the entity does not have any contents we are looking for if ( ( touch->contents & contentMask ) == 0 ) { continue; } // if the entity has no new contents flags if ( ( touch->contents & contents ) == touch->contents ) { continue; } idClip::numContents++; if ( collisionModelManager->Contents( start, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ) ) { contents |= ( touch->contents & contentMask ); } } return contents; }
/* ============ 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::Contacts ============ */ int idClip::Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { int i, j, num, n, numContacts; idClipModel *touch, *clipModelList[MAX_GENTITIES]; idBounds traceBounds; const idTraceModel *trm; trm = TraceModelForClipModel( mdl ); if( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { // test world idClip::numContacts++; numContacts = collisionModelManager->Contacts( contacts, maxContacts, start, dir, depth, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); } else { numContacts = 0; } for( i = 0; i < numContacts; i++ ) { contacts[i].entityNum = ENTITYNUM_WORLD; contacts[i].id = 0; } if( numContacts >= maxContacts ) { return numContacts; } if( !trm ) { traceBounds = idBounds( start ).Expand( depth ); } else { traceBounds.FromTransformedBounds( trm->bounds, start, trmAxis ); traceBounds.ExpandSelf( depth ); } num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); for( i = 0; i < num; i++ ) { touch = clipModelList[i]; if( !touch ) { continue; } // no contacts with render models if( touch->renderModelHandle != -1 ) { continue; } idClip::numContacts++; n = collisionModelManager->Contacts( contacts + numContacts, maxContacts - numContacts, start, dir, depth, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ); for( j = 0; j < n; j++ ) { contacts[numContacts].entityNum = touch->entity->entityNumber; contacts[numContacts].id = touch->id; numContacts++; } if( numContacts >= maxContacts ) { break; } } return numContacts; }
/* ============ idClip::Rotation ============ */ bool idClip::Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { int i, num; idClipModel *touch, *clipModelList[MAX_GENTITIES]; idBounds traceBounds; trace_t trace; const idTraceModel *trm; trm = TraceModelForClipModel( mdl ); if( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { // test world idClip::numRotations++; collisionModelManager->Rotation( &results, start, rotation, 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 = start; results.endAxis = trmAxis * rotation.ToMat3(); } if( !trm ) { traceBounds.FromPointRotation( start, rotation ); } else { traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation ); } num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); for( i = 0; i < num; i++ ) { touch = clipModelList[i]; if( !touch ) { continue; } // no rotational collision with render models if( touch->renderModelHandle != -1 ) { continue; } idClip::numRotations++; collisionModelManager->Rotation( &trace, start, rotation, 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::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 ); }