//----------------------------------------------------------------------------- // Computes the surrounding collision bounds based on whatever algorithm we want... //----------------------------------------------------------------------------- void CCollisionProperty::ComputeSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) { if (( GetSolid() == SOLID_CUSTOM ) && (m_nSurroundType != USE_GAME_CODE )) { // NOTE: This can only happen in transition periods, say during network // reception on the client. We expect USE_GAME_CODE to be used with SOLID_CUSTOM *pVecWorldMins = GetCollisionOrigin(); *pVecWorldMaxs = *pVecWorldMins; return; } switch( m_nSurroundType ) { case USE_OBB_COLLISION_BOUNDS: { Assert( GetSolid() != SOLID_CUSTOM ); bool bUseVPhysics = false; if ( ( GetSolid() == SOLID_VPHYSICS ) && ( GetOuter()->GetMoveType() == MOVETYPE_VPHYSICS ) ) { // UNDONE: This may not be necessary any more. IPhysicsObject *pPhysics = GetOuter()->VPhysicsGetObject(); bUseVPhysics = pPhysics && pPhysics->IsAsleep(); } ComputeCollisionSurroundingBox( bUseVPhysics, pVecWorldMins, pVecWorldMaxs ); } break; case USE_BEST_COLLISION_BOUNDS: Assert( GetSolid() != SOLID_CUSTOM ); ComputeCollisionSurroundingBox( (GetSolid() == SOLID_VPHYSICS), pVecWorldMins, pVecWorldMaxs ); break; case USE_COLLISION_BOUNDS_NEVER_VPHYSICS: Assert( GetSolid() != SOLID_CUSTOM ); ComputeCollisionSurroundingBox( false, pVecWorldMins, pVecWorldMaxs ); break; case USE_HITBOXES: ComputeHitboxSurroundingBox( pVecWorldMins, pVecWorldMaxs ); break; case USE_ROTATION_EXPANDED_BOUNDS: ComputeRotationExpandedBounds( pVecWorldMins, pVecWorldMaxs ); break; case USE_SPECIFIED_BOUNDS: VectorAdd( GetCollisionOrigin(), m_vecSpecifiedSurroundingMins, *pVecWorldMins ); VectorAdd( GetCollisionOrigin(), m_vecSpecifiedSurroundingMaxs, *pVecWorldMaxs ); break; case USE_GAME_CODE: GetOuter()->ComputeWorldSpaceSurroundingBox( pVecWorldMins, pVecWorldMaxs ); Assert( pVecWorldMins->x <= pVecWorldMaxs->x ); Assert( pVecWorldMins->y <= pVecWorldMaxs->y ); Assert( pVecWorldMins->z <= pVecWorldMaxs->z ); return; } #ifdef DEBUG /* // For debugging purposes, make sure the bounds actually does surround the thing. // Otherwise the optimization we were using isn't really all that great, is it? Vector vecTestMins, vecTestMaxs; ComputeCollisionSurroundingBox( (GetSolid() == SOLID_VPHYSICS), &vecTestMins, &vecTestMaxs ); // Now that we have the basics, let's expand for hitboxes if appropriate Vector vecWorldHitboxMins, vecWorldHitboxMaxs; if ( ComputeHitboxSurroundingBox( &vecWorldHitboxMins, &vecWorldHitboxMaxs ) ) { VectorMin( vecWorldHitboxMaxs, vecTestMins, vecTestMins ); VectorMax( vecWorldHitboxMaxs, vecTestMaxs, vecTestMaxs ); } Assert( vecTestMins.x >= pVecWorldMins->x && vecTestMins.y >= pVecWorldMins->y && vecTestMins.z >= pVecWorldMins->z ); Assert( vecTestMaxs.x <= pVecWorldMaxs->x && vecTestMaxs.y <= pVecWorldMaxs->y && vecTestMaxs.z <= pVecWorldMaxs->z ); */ #endif }
void CCollisionProperty::ComputeSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) { if (( GetSolid() == SOLID_CUSTOM ) && (m_nSurroundType != USE_GAME_CODE )) { // NOTE: This can only happen in transition periods, say during network // reception on the client. We expect USE_GAME_CODE to be used with SOLID_CUSTOM *pVecWorldMins = GetCollisionOrigin(); *pVecWorldMaxs = *pVecWorldMins; return; } switch( m_nSurroundType ) { case USE_OBB_COLLISION_BOUNDS: Assert( GetSolid() != SOLID_CUSTOM ); ComputeOBBBounds( pVecWorldMins, pVecWorldMaxs ); break; case USE_BEST_COLLISION_BOUNDS: Assert( GetSolid() != SOLID_CUSTOM ); ComputeCollisionSurroundingBox( (GetSolid() == SOLID_VPHYSICS), pVecWorldMins, pVecWorldMaxs ); break; case USE_ROTATION_EXPANDED_SEQUENCE_BOUNDS: ComputeRotationExpandedSequenceBounds( pVecWorldMins, pVecWorldMaxs ); break; case USE_COLLISION_BOUNDS_NEVER_VPHYSICS: Assert( GetSolid() != SOLID_CUSTOM ); ComputeCollisionSurroundingBox( false, pVecWorldMins, pVecWorldMaxs ); break; case USE_HITBOXES: ComputeHitboxSurroundingBox( pVecWorldMins, pVecWorldMaxs ); break; case USE_ROTATION_EXPANDED_BOUNDS: ComputeRotationExpandedBounds( pVecWorldMins, pVecWorldMaxs ); break; case USE_SPECIFIED_BOUNDS: VectorAdd( GetCollisionOrigin(), m_vecSpecifiedSurroundingMins, *pVecWorldMins ); VectorAdd( GetCollisionOrigin(), m_vecSpecifiedSurroundingMaxs, *pVecWorldMaxs ); break; case USE_GAME_CODE: GetOuter()->ComputeWorldSpaceSurroundingBox( pVecWorldMins, pVecWorldMaxs ); Assert( pVecWorldMins->x <= pVecWorldMaxs->x ); Assert( pVecWorldMins->y <= pVecWorldMaxs->y ); Assert( pVecWorldMins->z <= pVecWorldMaxs->z ); return; } //#ifdef DEBUG #ifdef CLIENT_DLL if ( cl_show_bounds_errors.GetBool() && ( m_nSurroundType == USE_ROTATION_EXPANDED_SEQUENCE_BOUNDS ) ) { // For debugging purposes, make sure the bounds actually does surround the thing. // Otherwise the optimization we were using isn't really all that great, is it? Vector vecTestMins, vecTestMaxs; if ( GetOuter()->GetBaseAnimating() ) { GetOuter()->GetBaseAnimating()->InvalidateBoneCache(); } ComputeHitboxSurroundingBox( &vecTestMins, &vecTestMaxs ); Assert( vecTestMins.x >= pVecWorldMins->x && vecTestMins.y >= pVecWorldMins->y && vecTestMins.z >= pVecWorldMins->z ); Assert( vecTestMaxs.x <= pVecWorldMaxs->x && vecTestMaxs.y <= pVecWorldMaxs->y && vecTestMaxs.z <= pVecWorldMaxs->z ); if ( vecTestMins.x < pVecWorldMins->x || vecTestMins.y < pVecWorldMins->y || vecTestMins.z < pVecWorldMins->z || vecTestMaxs.x > pVecWorldMaxs->x || vecTestMaxs.y > pVecWorldMaxs->y || vecTestMaxs.z > pVecWorldMaxs->z ) { const char *pSeqName = "<unknown seq>"; C_BaseAnimating *pAnim = GetOuter()->GetBaseAnimating(); if ( pAnim ) { int nSequence = pAnim->GetSequence(); pSeqName = pAnim->GetSequenceName( nSequence ); } Warning( "*** Bounds problem, index %d Eng %s, Seqeuence %s ", GetOuter()->entindex(), GetOuter()->GetClassname(), pSeqName ); Vector vecDelta = *pVecWorldMins - vecTestMins; Vector vecDelta2 = vecTestMaxs - *pVecWorldMaxs; if ( vecDelta.x > 0.0f || vecDelta2.x > 0.0f || vecDelta.y > 0.0f || vecDelta2.y > 0.0f ) { Msg( "Outside X/Y by %.2f ", MAX( MAX( vecDelta.x, vecDelta2.x ), MAX( vecDelta.y, vecDelta2.y ) ) ); } if ( vecDelta.z > 0.0f || vecDelta2.z > 0.0f ) { Msg( "Outside Z by (below) %.2f, (above) %.2f ", MAX( vecDelta.z, 0.0f ), MAX( vecDelta2.z, 0.0f ) ); } Msg( "\n" ); char pTemp[MAX_PATH]; Q_snprintf( pTemp, sizeof(pTemp), "%s [seq: %s]", GetOuter()->GetClassname(), pSeqName ); debugoverlay->AddBoxOverlay( vec3_origin, vecTestMins, vecTestMaxs, vec3_angle, 255, 0, 0, 0, 2 ); debugoverlay->AddBoxOverlay( vec3_origin, *pVecWorldMins, *pVecWorldMaxs, vec3_angle, 0, 0, 255, 0, 2 ); debugoverlay->AddTextOverlay( ( vecTestMins + vecTestMaxs ) * 0.5f, 2, pTemp ); } } #endif //#endif }