157 lines
5.4 KiB
C++
157 lines
5.4 KiB
C++
//========= Copyright © Valve Corporation, All rights reserved. ============//
|
|
// This is analogous to RnWorld from source2, but only for softbodies
|
|
//
|
|
#include "mathlib/softbodyenvironment.h"
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------------
|
|
CSoftbodyCollisionFilter::CSoftbodyCollisionFilter()
|
|
{
|
|
V_memset( m_GroupPairs, 0, sizeof( m_GroupPairs ) );
|
|
|
|
// Allow default-default shape collision by default to avoid confusion,
|
|
// in test worlds that won't set up their own collision filtering.
|
|
// INTERSECTION_COLLISION_GROUP_ALWAYS is the default collision group
|
|
InitGroup( COLLISION_GROUP_ALWAYS, INTERSECTION_PAIR_DEFAULT_COLLISION );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------------
|
|
uint16 CSoftbodyCollisionFilter::TestSimulation( const RnCollisionAttr_t &left, const RnCollisionAttr_t &right )const
|
|
{
|
|
Assert( left.m_nCollisionGroup < MAX_GROUPS && right.m_nCollisionGroup < MAX_GROUPS );
|
|
|
|
uint16 nIntersectionFlags = 0;
|
|
|
|
if ( left.IsSolidContactEnabled() && right.IsSolidContactEnabled() )
|
|
{
|
|
// Return value from a table of PxPairFlags.
|
|
nIntersectionFlags = m_GroupPairs[ left.m_nCollisionGroup ][ right.m_nCollisionGroup ];
|
|
}
|
|
|
|
if ( ( ( left.m_nInteractsAs & right.m_nInteractsExclude ) | ( left.m_nInteractsExclude & right.m_nInteractsAs ) ) != 0 )
|
|
{
|
|
nIntersectionFlags = 0;
|
|
}
|
|
else if ( ( ( left.m_nInteractsAs & right.m_nInteractsWith ) | ( left.m_nInteractsWith & right.m_nInteractsAs ) ) != 0 )
|
|
{
|
|
nIntersectionFlags |= INTERSECTION_PAIR_TRIGGER;
|
|
}
|
|
else if ( left.m_nCollisionGroup == COLLISION_GROUP_CONDITIONALLY_SOLID || right.m_nCollisionGroup == COLLISION_GROUP_CONDITIONALLY_SOLID )
|
|
{
|
|
nIntersectionFlags = 0;
|
|
}
|
|
|
|
if ( !left.IsTouchEventEnabled() || !right.IsTouchEventEnabled() )
|
|
{
|
|
nIntersectionFlags &= ~INTERSECTION_PAIR_TRIGGER;
|
|
}
|
|
|
|
// no interactions within the same hierarchy
|
|
// 0xFFFF is a special case because entindex() is -1 for all client-side-only entities
|
|
if ( left.m_nHierarchyId != 0 && left.m_nHierarchyId != 0xFFFF && left.m_nHierarchyId == right.m_nHierarchyId )
|
|
{
|
|
nIntersectionFlags = 0;
|
|
}
|
|
|
|
return nIntersectionFlags;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------------
|
|
void CSoftbodyCollisionFilter::InitGroup( int nGroup, CollisionGroupPairFlags defaultFlags )
|
|
{
|
|
for ( int i = 0; i < MAX_GROUPS; ++i )
|
|
{
|
|
m_GroupPairs[ i ][ nGroup ] = m_GroupPairs[ nGroup ][ i ] = defaultFlags;
|
|
}
|
|
m_GroupPairs[ COLLISION_GROUP_ALWAYS ][ nGroup ] = m_GroupPairs[ nGroup ][ COLLISION_GROUP_ALWAYS ] = INTERSECTION_PAIR_DEFAULT_COLLISION;
|
|
m_GroupPairs[ COLLISION_GROUP_TRIGGER ][ nGroup ] = m_GroupPairs[ nGroup ][ COLLISION_GROUP_TRIGGER ] = 0;
|
|
}
|
|
|
|
|
|
AABB_t CSoftbodyCollisionSphere::GetBbox()const
|
|
{
|
|
AABB_t aabb;
|
|
aabb.m_vMinBounds = m_vCenter - Vector( m_flRadius, m_flRadius, m_flRadius );
|
|
aabb.m_vMaxBounds = m_vCenter + Vector( m_flRadius, m_flRadius, m_flRadius );
|
|
return aabb;
|
|
}
|
|
|
|
AABB_t CSoftbodyCollisionCapsule::GetBbox()const
|
|
{
|
|
AABB_t aabb;
|
|
aabb.m_vMinBounds = VectorMin( m_vCenter[ 0 ], m_vCenter[ 1 ] ) - Vector( m_flRadius, m_flRadius, m_flRadius );
|
|
aabb.m_vMaxBounds = VectorMax( m_vCenter[ 0 ], m_vCenter[ 1 ] ) + Vector( m_flRadius, m_flRadius, m_flRadius );
|
|
return aabb;
|
|
}
|
|
|
|
|
|
void CSoftbodyEnvironment::Add( CSoftbodyCollisionShape * pShape )
|
|
{
|
|
if ( pShape->GetProxyId() >= 0 )
|
|
return; // already added
|
|
|
|
AABB_t bbox = pShape->GetBbox();
|
|
// bbox.Expand( 8 ); // when we add the shape for the first time, we might not know if it's going to move at all - so a good heuristic might be to NOT expand the proxy bounds at first
|
|
|
|
int32 nProxyId = m_BroadphaseTree.CreateProxy( bbox, pShape );
|
|
pShape->SetProxyId( nProxyId );
|
|
}
|
|
|
|
|
|
void CSoftbodyEnvironment::Update( CSoftbodyCollisionShape * pShape )
|
|
{
|
|
int32 nProxyId = pShape->GetProxyId();
|
|
if ( nProxyId < 0 )
|
|
return; // proxy not added to the broadphase
|
|
|
|
// Did the bbox move enough to warrant moving the proxy?
|
|
AABB_t bbox = pShape->GetBbox();
|
|
if ( !m_BroadphaseTree.GetBounds( nProxyId).Contains( bbox ) )
|
|
{
|
|
bbox.Expand( 8 ); // we moved the proxy... maybe a good heuristic here would be to keep track of movements and expand adaptively, depending on how much the proxy moves
|
|
m_BroadphaseTree.MoveProxy( nProxyId, bbox );
|
|
}
|
|
}
|
|
|
|
|
|
void CSoftbodyEnvironment::AddOrUpdate( CSoftbodyCollisionShape * pShape )
|
|
{
|
|
int32 nProxyId = pShape->GetProxyId();
|
|
// Did the bbox move enough to warrant moving the proxy?
|
|
AABB_t bbox = pShape->GetBbox();
|
|
if ( nProxyId < 0 )
|
|
{
|
|
int32 nProxyId = m_BroadphaseTree.CreateProxy( bbox, pShape );
|
|
pShape->SetProxyId( nProxyId );
|
|
}
|
|
else if ( !m_BroadphaseTree.GetBounds( nProxyId ).Contains( bbox ) )
|
|
{
|
|
bbox.Expand( 8 ); // we moved the proxy... maybe a good heuristic here would be to keep track of movements and expand adaptively, depending on how much the proxy moves
|
|
m_BroadphaseTree.MoveProxy( nProxyId, bbox );
|
|
}
|
|
}
|
|
|
|
void CSoftbodyEnvironment::Remove( CSoftbodyCollisionShape * pShape )
|
|
{
|
|
int nProxyId = pShape->GetProxyId();
|
|
if ( nProxyId >= 0 )
|
|
{
|
|
m_BroadphaseTree.DestroyProxy( pShape->GetProxyId() );
|
|
pShape->SetProxyId( -1 );
|
|
}
|
|
}
|
|
|
|
void CSoftbodyEnvironment::SetWind( const Vector & vWind )
|
|
{
|
|
float flStrength = vWind.Length();
|
|
if ( fabsf( m_vWindDesc.w ) < FLT_EPSILON )
|
|
{
|
|
SetNoWind();
|
|
}
|
|
else
|
|
{
|
|
m_vWindDesc.Init( vWind / flStrength, flStrength );
|
|
}
|
|
}
|