You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
6.4 KiB
238 lines
6.4 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "physics.h" |
|
#include "te_effect_dispatch.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
static int BestAxisMatchingNormal( matrix3x4_t &matrix, const Vector &normal ) |
|
{ |
|
float bestDot = -1; |
|
int best = 0; |
|
for ( int i = 0; i < 3; i++ ) |
|
{ |
|
Vector tmp; |
|
MatrixGetColumn( matrix, i, tmp ); |
|
float dot = fabs(DotProduct( tmp, normal )); |
|
if ( dot > bestDot ) |
|
{ |
|
bestDot = dot; |
|
best = i; |
|
} |
|
} |
|
|
|
return best; |
|
} |
|
|
|
void PhysicsSplash( IPhysicsFluidController *pFluid, IPhysicsObject *pObject, CBaseEntity *pEntity ) |
|
{ |
|
Vector normal; |
|
float dist; |
|
pFluid->GetSurfacePlane( &normal, &dist ); |
|
|
|
matrix3x4_t &matrix = pEntity->EntityToWorldTransform(); |
|
|
|
// Find the local axis that best matches the water surface normal |
|
int bestAxis = BestAxisMatchingNormal( matrix, normal ); |
|
|
|
Vector tangent, binormal; |
|
MatrixGetColumn( matrix, (bestAxis+1)%3, tangent ); |
|
binormal = CrossProduct( normal, tangent ); |
|
VectorNormalize( binormal ); |
|
tangent = CrossProduct( binormal, normal ); |
|
VectorNormalize( tangent ); |
|
|
|
// Now we have a basis tangent to the surface that matches the object's local orientation as well as possible |
|
// compute an OBB using this basis |
|
|
|
// Get object extents in basis |
|
Vector tanPts[2], binPts[2]; |
|
tanPts[0] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), -tangent ); |
|
tanPts[1] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), tangent ); |
|
binPts[0] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), -binormal ); |
|
binPts[1] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), binormal ); |
|
|
|
// now compute the centered bbox |
|
float mins[2], maxs[2], center[2], extents[2]; |
|
mins[0] = DotProduct( tanPts[0], tangent ); |
|
maxs[0] = DotProduct( tanPts[1], tangent ); |
|
|
|
mins[1] = DotProduct( binPts[0], binormal ); |
|
maxs[1] = DotProduct( binPts[1], binormal ); |
|
|
|
center[0] = 0.5 * (mins[0] + maxs[0]); |
|
center[1] = 0.5 * (mins[1] + maxs[1]); |
|
|
|
extents[0] = maxs[0] - center[0]; |
|
extents[1] = maxs[1] - center[1]; |
|
|
|
Vector centerPoint = center[0] * tangent + center[1] * binormal + dist * normal; |
|
|
|
Vector axes[2]; |
|
axes[0] = (maxs[0] - center[0]) * tangent; |
|
axes[1] = (maxs[1] - center[1]) * binormal; |
|
|
|
// visualize OBB hit |
|
/* |
|
Vector corner1 = centerPoint - axes[0] - axes[1]; |
|
Vector corner2 = centerPoint + axes[0] - axes[1]; |
|
Vector corner3 = centerPoint + axes[0] + axes[1]; |
|
Vector corner4 = centerPoint - axes[0] + axes[1]; |
|
NDebugOverlay::Line( corner1, corner2, 0, 0, 255, false, 10 ); |
|
NDebugOverlay::Line( corner2, corner3, 0, 0, 255, false, 10 ); |
|
NDebugOverlay::Line( corner3, corner4, 0, 0, 255, false, 10 ); |
|
NDebugOverlay::Line( corner4, corner1, 0, 0, 255, false, 10 ); |
|
*/ |
|
|
|
Vector corner[4]; |
|
|
|
corner[0] = centerPoint - axes[0] - axes[1]; |
|
corner[1] = centerPoint + axes[0] - axes[1]; |
|
corner[2] = centerPoint + axes[0] + axes[1]; |
|
corner[3] = centerPoint - axes[0] + axes[1]; |
|
|
|
CEffectData data; |
|
|
|
if ( pObject->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL ) |
|
{ |
|
/* |
|
data.m_vOrigin = centerPoint; |
|
data.m_vNormal = normal; |
|
VectorAngles( normal, data.m_vAngles ); |
|
data.m_flScale = random->RandomFloat( 8, 10 ); |
|
|
|
DispatchEffect( "watersplash", data ); |
|
|
|
int splashes = 4; |
|
Vector point; |
|
|
|
for ( int i = 0; i < splashes; i++ ) |
|
{ |
|
point = RandomVector( -32.0f, 32.0f ); |
|
point[2] = 0.0f; |
|
|
|
point += corner[i]; |
|
|
|
data.m_vOrigin = point; |
|
data.m_vNormal = normal; |
|
VectorAngles( normal, data.m_vAngles ); |
|
data.m_flScale = random->RandomFloat( 4, 6 ); |
|
|
|
DispatchEffect( "watersplash", data ); |
|
} |
|
*/ |
|
|
|
//FIXME: This code will not work correctly given how the ragdoll/fluid collision is acting currently |
|
return; |
|
} |
|
|
|
Vector vel; |
|
pObject->GetVelocity( &vel, NULL ); |
|
float rawSpeed = -DotProduct( normal, vel ); |
|
|
|
// proportional to cross-sectional area times velocity squared (fluid pressure) |
|
float speed = rawSpeed * rawSpeed * extents[0] * extents[1] * (1.0f / 2500000.0f) * pObject->GetMass() * (0.01f); |
|
|
|
speed = clamp( speed, 0.f, 50.f ); |
|
|
|
bool bRippleOnly = false; |
|
|
|
// allow the entity to perform a custom splash effect |
|
if ( pEntity->PhysicsSplash( centerPoint, normal, rawSpeed, speed ) ) |
|
return; |
|
|
|
//Deny really weak hits |
|
//FIXME: We still need to ripple the surface in this case |
|
if ( speed <= 0.35f ) |
|
{ |
|
if ( speed <= 0.1f ) |
|
return; |
|
|
|
bRippleOnly = true; |
|
} |
|
|
|
float size = RemapVal( speed, 0.35, 50, 8, 18 ); |
|
|
|
//Find the surface area |
|
float radius = extents[0] * extents[1]; |
|
//int splashes = clamp ( radius / 128.0f, 1, 2 ); //One splash for every three square feet of area |
|
|
|
//Msg( "Speed: %.2f, Size: %.2f\n, Radius: %.2f, Splashes: %d", speed, size, radius, splashes ); |
|
|
|
Vector point; |
|
|
|
data.m_fFlags = 0; |
|
data.m_vOrigin = centerPoint; |
|
data.m_vNormal = normal; |
|
VectorAngles( normal, data.m_vAngles ); |
|
data.m_flScale = size + random->RandomFloat( 0, 2 ); |
|
if ( pEntity->GetWaterType() & CONTENTS_SLIME ) |
|
{ |
|
data.m_fFlags |= FX_WATER_IN_SLIME; |
|
} |
|
|
|
if ( bRippleOnly ) |
|
{ |
|
DispatchEffect( "waterripple", data ); |
|
} |
|
else |
|
{ |
|
DispatchEffect( "watersplash", data ); |
|
} |
|
|
|
if ( radius > 500.0f ) |
|
{ |
|
int splashes = random->RandomInt( 1, 4 ); |
|
|
|
for ( int i = 0; i < splashes; i++ ) |
|
{ |
|
point = RandomVector( -4.0f, 4.0f ); |
|
point[2] = 0.0f; |
|
|
|
point += corner[i]; |
|
|
|
data.m_fFlags = 0; |
|
data.m_vOrigin = point; |
|
data.m_vNormal = normal; |
|
VectorAngles( normal, data.m_vAngles ); |
|
data.m_flScale = size + random->RandomFloat( -3, 1 ); |
|
if ( pEntity->GetWaterType() & CONTENTS_SLIME ) |
|
{ |
|
data.m_fFlags |= FX_WATER_IN_SLIME; |
|
} |
|
|
|
if ( bRippleOnly ) |
|
{ |
|
DispatchEffect( "waterripple", data ); |
|
} |
|
else |
|
{ |
|
DispatchEffect( "watersplash", data ); |
|
} |
|
} |
|
} |
|
|
|
/* |
|
for ( i = 0; i < splashes; i++ ) |
|
{ |
|
point = RandomVector( -8.0f, 8.0f ); |
|
point[2] = 0.0f; |
|
|
|
point += centerPoint + axes[0] * random->RandomFloat( -1, 1 ) + axes[1] * random->RandomFloat( -1, 1 ); |
|
|
|
data.m_vOrigin = point; |
|
data.m_vNormal = normal; |
|
VectorAngles( normal, data.m_vAngles ); |
|
data.m_flScale = size + random->RandomFloat( -2, 4 ); |
|
|
|
DispatchEffect( "watersplash", data ); |
|
} |
|
*/ |
|
}
|
|
|