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.
503 lines
17 KiB
503 lines
17 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef COLLISIONPROPERTY_H |
|
#define COLLISIONPROPERTY_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "networkvar.h" |
|
#include "engine/ICollideable.h" |
|
#include "mathlib/vector.h" |
|
#include "ispatialpartition.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Forward declarations |
|
//----------------------------------------------------------------------------- |
|
class CBaseEntity; |
|
class IHandleEntity; |
|
class QAngle; |
|
class Vector; |
|
struct Ray_t; |
|
class IPhysicsObject; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Force spatial partition updates (to avoid threading problems caused by lazy update) |
|
//----------------------------------------------------------------------------- |
|
void UpdateDirtySpatialPartitionEntities(); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Specifies how to compute the surrounding box |
|
//----------------------------------------------------------------------------- |
|
enum SurroundingBoundsType_t |
|
{ |
|
USE_OBB_COLLISION_BOUNDS = 0, |
|
USE_BEST_COLLISION_BOUNDS, // Always use the best bounds (most expensive) |
|
USE_HITBOXES, |
|
USE_SPECIFIED_BOUNDS, |
|
USE_GAME_CODE, |
|
USE_ROTATION_EXPANDED_BOUNDS, |
|
USE_COLLISION_BOUNDS_NEVER_VPHYSICS, |
|
|
|
SURROUNDING_TYPE_BIT_COUNT = 3 |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Encapsulates collision representation for an entity |
|
//----------------------------------------------------------------------------- |
|
class CCollisionProperty : public ICollideable |
|
{ |
|
DECLARE_CLASS_NOBASE( CCollisionProperty ); |
|
DECLARE_EMBEDDED_NETWORKVAR(); |
|
DECLARE_PREDICTABLE(); |
|
|
|
#ifdef GAME_DLL |
|
DECLARE_DATADESC(); |
|
#endif |
|
|
|
public: |
|
CCollisionProperty(); |
|
~CCollisionProperty(); |
|
|
|
void Init( CBaseEntity *pEntity ); |
|
|
|
// Methods of ICollideable |
|
virtual IHandleEntity *GetEntityHandle(); |
|
virtual const Vector& OBBMinsPreScaled() const { return m_vecMinsPreScaled.Get(); } |
|
virtual const Vector& OBBMaxsPreScaled() const { return m_vecMaxsPreScaled.Get(); } |
|
virtual const Vector& OBBMins() const { return m_vecMins.Get(); } |
|
virtual const Vector& OBBMaxs() const { return m_vecMaxs.Get(); } |
|
virtual void WorldSpaceTriggerBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) const; |
|
virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); |
|
virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); |
|
virtual int GetCollisionModelIndex(); |
|
virtual const model_t* GetCollisionModel(); |
|
virtual const Vector& GetCollisionOrigin() const; |
|
virtual const QAngle& GetCollisionAngles() const; |
|
virtual const matrix3x4_t& CollisionToWorldTransform() const; |
|
virtual SolidType_t GetSolid() const; |
|
virtual int GetSolidFlags() const; |
|
virtual IClientUnknown* GetIClientUnknown(); |
|
virtual int GetCollisionGroup() const; |
|
virtual void WorldSpaceSurroundingBounds( Vector *pVecMins, Vector *pVecMaxs ); |
|
virtual bool ShouldTouchTrigger( int triggerSolidFlags ) const; |
|
virtual const matrix3x4_t *GetRootParentToWorldTransform() const; |
|
|
|
public: |
|
// Spatial partition management |
|
void CreatePartitionHandle(); |
|
void DestroyPartitionHandle(); |
|
unsigned short GetPartitionHandle() const; |
|
|
|
// Marks the spatial partition dirty |
|
void MarkPartitionHandleDirty(); |
|
|
|
// Sets the collision bounds + the size (OBB) |
|
void SetCollisionBounds( const Vector& mins, const Vector &maxs ); |
|
|
|
// Rebuilds the scaled bounds from the pre-scaled bounds after a model's scale has changed |
|
void RefreshScaledCollisionBounds( void ); |
|
|
|
// Sets special trigger bounds. The bloat amount indicates how much bigger the |
|
// trigger bounds should be beyond the bounds set in SetCollisionBounds |
|
// This method will also set the FSOLID flag FSOLID_USE_TRIGGER_BOUNDS |
|
void UseTriggerBounds( bool bEnable, float flBloat = 0.0f ); |
|
|
|
// Sets the method by which the surrounding collision bounds is set |
|
// You must pass in values for mins + maxs if you select the USE_SPECIFIED_BOUNDS type. |
|
void SetSurroundingBoundsType( SurroundingBoundsType_t type, const Vector *pMins = NULL, const Vector *pMaxs = NULL ); |
|
|
|
// Sets the solid type (which type of collision representation) |
|
void SetSolid( SolidType_t val ); |
|
|
|
// Methods related to size. The OBB here is measured in CollisionSpace |
|
// (specified by GetCollisionToWorld) |
|
const Vector& OBBSize( ) const; |
|
|
|
// Returns a radius (or the square of the radius) of a sphere |
|
// *centered at the world space center* bounding the collision representation |
|
// of the entity. NOTE: The world space center *may* move when the entity rotates. |
|
float BoundingRadius() const; |
|
float BoundingRadius2D() const; |
|
|
|
// Returns the center of the OBB in collision space |
|
const Vector & OBBCenter( ) const; |
|
|
|
// center point of entity measured in world space |
|
// NOTE: This point *may* move when the entity moves depending on |
|
// which solid type is being used. |
|
const Vector & WorldSpaceCenter( ) const; |
|
|
|
// Methods related to solid flags |
|
void ClearSolidFlags( void ); |
|
void RemoveSolidFlags( int flags ); |
|
void AddSolidFlags( int flags ); |
|
bool IsSolidFlagSet( int flagMask ) const; |
|
void SetSolidFlags( int flags ); |
|
bool IsSolid() const; |
|
|
|
// Updates the spatial partition |
|
void UpdatePartition( ); |
|
|
|
// Are the bounds defined in entity space? |
|
bool IsBoundsDefinedInEntitySpace() const; |
|
|
|
// Transforms a point in OBB space to world space |
|
const Vector & CollisionToWorldSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Transforms a point in world space to OBB space |
|
const Vector & WorldToCollisionSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Transforms a direction in world space to OBB space |
|
const Vector & WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Selects a random point in the bounds given the normalized 0-1 bounds |
|
void RandomPointInBounds( const Vector &vecNormalizedMins, const Vector &vecNormalizedMaxs, Vector *pPoint) const; |
|
|
|
// Is a worldspace point within the bounds of the OBB? |
|
bool IsPointInBounds( const Vector &vecWorldPt ) const; |
|
|
|
// Computes a bounding box in world space surrounding the collision bounds |
|
void WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const; |
|
|
|
// Get the collision space mins directly |
|
const Vector & CollisionSpaceMins( void ) const; |
|
|
|
// Get the collision space maxs directly |
|
const Vector & CollisionSpaceMaxs( void ) const; |
|
|
|
// Computes a "normalized" point (range 0,0,0 - 1,1,1) in collision space |
|
// Useful for things like getting a point 75% of the way along z on the OBB, for example |
|
const Vector & NormalizedToCollisionSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Computes a "normalized" point (range 0,0,0 - 1,1,1) in world space |
|
const Vector & NormalizedToWorldSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Transforms a point in world space to normalized space |
|
const Vector & WorldToNormalizedSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Transforms a point in collision space to normalized space |
|
const Vector & CollisionToNormalizedSpace( const Vector &in, Vector *pResult ) const; |
|
|
|
// Computes the nearest point in the OBB to a point specified in world space |
|
void CalcNearestPoint( const Vector &vecWorldPt, Vector *pVecNearestWorldPt ) const; |
|
|
|
// Computes the distance from a point in world space to the OBB |
|
float CalcDistanceFromPoint( const Vector &vecWorldPt ) const; |
|
|
|
// Does a rotation make us need to recompute the surrounding box? |
|
bool DoesRotationInvalidateSurroundingBox( ) const; |
|
|
|
// Does VPhysicsUpdate make us need to recompute the surrounding box? |
|
bool DoesVPhysicsInvalidateSurroundingBox( ) const; |
|
|
|
// Marks the entity has having a dirty surrounding box |
|
void MarkSurroundingBoundsDirty(); |
|
|
|
// Compute the largest dot product of the OBB and the specified direction vector |
|
float ComputeSupportMap( const Vector &vecDirection ) const; |
|
|
|
private: |
|
// Transforms an AABB measured in collision space to a box that surrounds it in world space |
|
void CollisionAABBToWorldAABB( const Vector &entityMins, const Vector &entityMaxs, Vector *pWorldMins, Vector *pWorldMaxs ) const; |
|
|
|
// Expand trigger bounds.. |
|
void ComputeVPhysicsSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); |
|
|
|
// Expand trigger bounds.. |
|
bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); |
|
bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); |
|
|
|
// Computes the surrounding collision bounds based on whatever algorithm we want... |
|
void ComputeCollisionSurroundingBox( bool bUseVPhysics, Vector *pVecWorldMins, Vector *pVecWorldMaxs ); |
|
|
|
// Computes the surrounding collision bounds from the the OBB (not vphysics) |
|
void ComputeRotationExpandedBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); |
|
|
|
// Computes the surrounding collision bounds based on whatever algorithm we want... |
|
void ComputeSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); |
|
|
|
// Check for untouch |
|
void CheckForUntouch(); |
|
|
|
// Updates the spatial partition |
|
void UpdateServerPartitionMask( ); |
|
|
|
// Outer |
|
CBaseEntity *GetOuter(); |
|
const CBaseEntity *GetOuter() const; |
|
|
|
private: |
|
CBaseEntity *m_pOuter; |
|
|
|
CNetworkVector( m_vecMinsPreScaled ); |
|
CNetworkVector( m_vecMaxsPreScaled ); |
|
CNetworkVector( m_vecMins ); |
|
CNetworkVector( m_vecMaxs ); |
|
float m_flRadius; |
|
|
|
CNetworkVar( unsigned short, m_usSolidFlags ); |
|
|
|
// Spatial partition |
|
SpatialPartitionHandle_t m_Partition; |
|
CNetworkVar( unsigned char, m_nSurroundType ); |
|
|
|
// One of the SOLID_ defines. Use GetSolid/SetSolid. |
|
CNetworkVar( unsigned char, m_nSolidType ); |
|
CNetworkVar( unsigned char , m_triggerBloat ); |
|
|
|
// SUCKY: We didn't use to have to store this previously |
|
// but storing it here means that we can network it + avoid a ton of |
|
// client-side mismatch problems |
|
CNetworkVector( m_vecSpecifiedSurroundingMinsPreScaled ); |
|
CNetworkVector( m_vecSpecifiedSurroundingMaxsPreScaled ); |
|
CNetworkVector( m_vecSpecifiedSurroundingMins ); |
|
CNetworkVector( m_vecSpecifiedSurroundingMaxs ); |
|
|
|
// Cached off world-aligned surrounding bounds |
|
#if 0 |
|
short m_surroundingMins[3]; |
|
short m_surroundingMaxs[3]; |
|
#else |
|
Vector m_vecSurroundingMins; |
|
Vector m_vecSurroundingMaxs; |
|
#endif |
|
|
|
// pointer to the entity's physics object (vphysics.dll) |
|
//IPhysicsObject *m_pPhysicsObject; |
|
|
|
friend class CBaseEntity; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// For networking this bad boy |
|
//----------------------------------------------------------------------------- |
|
#ifdef CLIENT_DLL |
|
EXTERN_RECV_TABLE( DT_CollisionProperty ); |
|
#else |
|
EXTERN_SEND_TABLE( DT_CollisionProperty ); |
|
#endif |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Inline methods |
|
//----------------------------------------------------------------------------- |
|
inline CBaseEntity *CCollisionProperty::GetOuter() |
|
{ |
|
return m_pOuter; |
|
} |
|
|
|
inline const CBaseEntity *CCollisionProperty::GetOuter() const |
|
{ |
|
return m_pOuter; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Spatial partition |
|
//----------------------------------------------------------------------------- |
|
inline unsigned short CCollisionProperty::GetPartitionHandle() const |
|
{ |
|
return m_Partition; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Methods related to size |
|
//----------------------------------------------------------------------------- |
|
inline const Vector& CCollisionProperty::OBBSize( ) const |
|
{ |
|
// NOTE: Could precache this, but it's not used that often.. |
|
Vector &temp = AllocTempVector(); |
|
VectorSubtract( m_vecMaxs, m_vecMins, temp ); |
|
return temp; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Bounding radius size |
|
//----------------------------------------------------------------------------- |
|
inline float CCollisionProperty::BoundingRadius() const |
|
{ |
|
return m_flRadius; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Methods relating to solid flags |
|
//----------------------------------------------------------------------------- |
|
inline bool CCollisionProperty::IsBoundsDefinedInEntitySpace() const |
|
{ |
|
return (( m_usSolidFlags & FSOLID_FORCE_WORLD_ALIGNED ) == 0 ) && |
|
( m_nSolidType != SOLID_BBOX ) && ( m_nSolidType != SOLID_NONE ); |
|
} |
|
|
|
inline void CCollisionProperty::ClearSolidFlags( void ) |
|
{ |
|
SetSolidFlags( 0 ); |
|
} |
|
|
|
inline void CCollisionProperty::RemoveSolidFlags( int flags ) |
|
{ |
|
SetSolidFlags( m_usSolidFlags & ~flags ); |
|
} |
|
|
|
inline void CCollisionProperty::AddSolidFlags( int flags ) |
|
{ |
|
SetSolidFlags( m_usSolidFlags | flags ); |
|
} |
|
|
|
inline int CCollisionProperty::GetSolidFlags( void ) const |
|
{ |
|
return m_usSolidFlags; |
|
} |
|
|
|
inline bool CCollisionProperty::IsSolidFlagSet( int flagMask ) const |
|
{ |
|
return (m_usSolidFlags & flagMask) != 0; |
|
} |
|
|
|
inline bool CCollisionProperty::IsSolid() const |
|
{ |
|
return ::IsSolid( (SolidType_t)(unsigned char)m_nSolidType, m_usSolidFlags ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the center in OBB space |
|
//----------------------------------------------------------------------------- |
|
inline const Vector& CCollisionProperty::OBBCenter( ) const |
|
{ |
|
Vector &vecResult = AllocTempVector(); |
|
VectorLerp( m_vecMins, m_vecMaxs, 0.5f, vecResult ); |
|
return vecResult; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// center point of entity |
|
//----------------------------------------------------------------------------- |
|
inline const Vector &CCollisionProperty::WorldSpaceCenter( ) const |
|
{ |
|
Vector &vecResult = AllocTempVector(); |
|
CollisionToWorldSpace( OBBCenter(), &vecResult ); |
|
return vecResult; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Transforms a point in OBB space to world space |
|
//----------------------------------------------------------------------------- |
|
inline const Vector &CCollisionProperty::CollisionToWorldSpace( const Vector &in, Vector *pResult ) const |
|
{ |
|
// Makes sure we don't re-use the same temp twice |
|
if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) ) |
|
{ |
|
VectorAdd( in, GetCollisionOrigin(), *pResult ); |
|
} |
|
else |
|
{ |
|
VectorTransform( in, CollisionToWorldTransform(), *pResult ); |
|
} |
|
return *pResult; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Transforms a point in world space to OBB space |
|
//----------------------------------------------------------------------------- |
|
inline const Vector &CCollisionProperty::WorldToCollisionSpace( const Vector &in, Vector *pResult ) const |
|
{ |
|
if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) ) |
|
{ |
|
VectorSubtract( in, GetCollisionOrigin(), *pResult ); |
|
} |
|
else |
|
{ |
|
VectorITransform( in, CollisionToWorldTransform(), *pResult ); |
|
} |
|
return *pResult; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Transforms a direction in world space to OBB space |
|
//----------------------------------------------------------------------------- |
|
inline const Vector & CCollisionProperty::WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const |
|
{ |
|
if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) ) |
|
{ |
|
*pResult = in; |
|
} |
|
else |
|
{ |
|
VectorIRotate( in, CollisionToWorldTransform(), *pResult ); |
|
} |
|
return *pResult; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Computes a bounding box in world space surrounding the collision bounds |
|
//----------------------------------------------------------------------------- |
|
inline void CCollisionProperty::WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const |
|
{ |
|
CollisionAABBToWorldAABB( m_vecMins, m_vecMaxs, pWorldMins, pWorldMaxs ); |
|
} |
|
|
|
|
|
// Get the collision space mins directly |
|
inline const Vector & CCollisionProperty::CollisionSpaceMins( void ) const |
|
{ |
|
return m_vecMins; |
|
} |
|
|
|
// Get the collision space maxs directly |
|
inline const Vector & CCollisionProperty::CollisionSpaceMaxs( void ) const |
|
{ |
|
return m_vecMaxs; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Does a rotation make us need to recompute the surrounding box? |
|
//----------------------------------------------------------------------------- |
|
inline bool CCollisionProperty::DoesRotationInvalidateSurroundingBox( ) const |
|
{ |
|
if ( IsSolidFlagSet(FSOLID_ROOT_PARENT_ALIGNED) ) |
|
return true; |
|
|
|
switch ( m_nSurroundType ) |
|
{ |
|
case USE_COLLISION_BOUNDS_NEVER_VPHYSICS: |
|
case USE_OBB_COLLISION_BOUNDS: |
|
case USE_BEST_COLLISION_BOUNDS: |
|
return IsBoundsDefinedInEntitySpace(); |
|
|
|
// In the case of game code, we don't really know, so we have to assume it does |
|
case USE_HITBOXES: |
|
case USE_GAME_CODE: |
|
return true; |
|
|
|
case USE_ROTATION_EXPANDED_BOUNDS: |
|
case USE_SPECIFIED_BOUNDS: |
|
return false; |
|
|
|
default: |
|
Assert(0); |
|
return true; |
|
} |
|
} |
|
|
|
|
|
#endif // COLLISIONPROPERTY_H
|
|
|