#ifndef COLLISIONPROPERTY_H #define COLLISIONPROPERTY_H #ifdef _WIN32 #pragma once #endif #include "networkvar.h" #include "ICollideable.h" #include "vector.h" #include "ispatialpartition.h" class CBaseEntity; class IHandleEntity; class QAngle; class Vector; struct Ray_t; class IPhysicsObject; void UpdateDirtySpatialPartitionEntities(); enum SurroundingBoundsType_t { USE_OBB_COLLISION_BOUNDS = 0, USE_BEST_COLLISION_BOUNDS, USE_HITBOXES, USE_SPECIFIED_BOUNDS, USE_GAME_CODE, USE_ROTATION_EXPANDED_BOUNDS, USE_COLLISION_BOUNDS_NEVER_VPHYSICS, SURROUNDING_TYPE_BIT_COUNT = 3 }; 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); 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: void CreatePartitionHandle(); void DestroyPartitionHandle(); unsigned short GetPartitionHandle() const; void MarkPartitionHandleDirty(); void SetCollisionBounds(const Vector& mins, const Vector& maxs); void RefreshScaledCollisionBounds(void); void UseTriggerBounds(bool bEnable, float flBloat = 0.0f); void SetSurroundingBoundsType(SurroundingBoundsType_t type, const Vector* pMins = NULL, const Vector* pMaxs = NULL); void SetSolid(SolidType_t val); const Vector& OBBSize() const; float BoundingRadius() const; float BoundingRadius2D() const; const Vector& OBBCenter() const; const Vector& WorldSpaceCenter() const; void ClearSolidFlags(void); void RemoveSolidFlags(int flags); void AddSolidFlags(int flags); bool IsSolidFlagSet(int flagMask) const; void SetSolidFlags(int flags); bool IsSolid() const; void UpdatePartition(); bool IsBoundsDefinedInEntitySpace() const; const Vector& CollisionToWorldSpace(const Vector& in, Vector* pResult) const; const Vector& WorldToCollisionSpace(const Vector& in, Vector* pResult) const; const Vector& WorldDirectionToCollisionSpace(const Vector& in, Vector* pResult) const; void RandomPointInBounds(const Vector& vecNormalizedMins, const Vector& vecNormalizedMaxs, Vector* pPoint) const; bool IsPointInBounds(const Vector& vecWorldPt) const; void WorldSpaceAABB(Vector* pWorldMins, Vector* pWorldMaxs) const; const Vector& CollisionSpaceMins(void) const; const Vector& CollisionSpaceMaxs(void) const; const Vector& NormalizedToCollisionSpace(const Vector& in, Vector* pResult) const; const Vector& NormalizedToWorldSpace(const Vector& in, Vector* pResult) const; const Vector& WorldToNormalizedSpace(const Vector& in, Vector* pResult) const; const Vector& CollisionToNormalizedSpace(const Vector& in, Vector* pResult) const; void CalcNearestPoint(const Vector& vecWorldPt, Vector* pVecNearestWorldPt) const; float CalcDistanceFromPoint(const Vector& vecWorldPt) const; bool DoesRotationInvalidateSurroundingBox() const; bool DoesVPhysicsInvalidateSurroundingBox() const; void MarkSurroundingBoundsDirty(); float ComputeSupportMap(const Vector& vecDirection) const; private: void CollisionAABBToWorldAABB(const Vector& entityMins, const Vector& entityMaxs, Vector* pWorldMins, Vector* pWorldMaxs) const; void ComputeVPhysicsSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); bool ComputeHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); bool ComputeEntitySpaceHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); void ComputeCollisionSurroundingBox(bool bUseVPhysics, Vector* pVecWorldMins, Vector* pVecWorldMaxs); void ComputeRotationExpandedBounds(Vector* pVecWorldMins, Vector* pVecWorldMaxs); void ComputeSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs); void CheckForUntouch(); void UpdateServerPartitionMask(); 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); SpatialPartitionHandle_t m_Partition; CNetworkVar(unsigned char, m_nSurroundType); CNetworkVar(unsigned char, m_nSolidType); CNetworkVar(unsigned char, m_triggerBloat); CNetworkVector(m_vecSpecifiedSurroundingMinsPreScaled); CNetworkVector(m_vecSpecifiedSurroundingMaxsPreScaled); CNetworkVector(m_vecSpecifiedSurroundingMins); CNetworkVector(m_vecSpecifiedSurroundingMaxs); #if 0 short m_surroundingMins[3]; short m_surroundingMaxs[3]; #else Vector m_vecSurroundingMins; Vector m_vecSurroundingMaxs; #endif friend class CBaseEntity; }; #ifdef CLIENT_DLL EXTERN_RECV_TABLE(DT_CollisionProperty); #else EXTERN_SEND_TABLE(DT_CollisionProperty); #endif inline CBaseEntity* CCollisionProperty::GetOuter() { return m_pOuter; } inline const CBaseEntity* CCollisionProperty::GetOuter() const { return m_pOuter; } inline unsigned short CCollisionProperty::GetPartitionHandle() const { return m_Partition; } inline const Vector& CCollisionProperty::OBBSize() const { Vector& temp = AllocTempVector(); VectorSubtract(m_vecMaxs, m_vecMins, temp); return temp; } inline float CCollisionProperty::BoundingRadius() const { return m_flRadius; } 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); } inline const Vector& CCollisionProperty::OBBCenter() const { Vector& vecResult = AllocTempVector(); VectorLerp(m_vecMins, m_vecMaxs, 0.5f, vecResult); return vecResult; } inline const Vector& CCollisionProperty::WorldSpaceCenter() const { Vector& vecResult = AllocTempVector(); CollisionToWorldSpace(OBBCenter(), &vecResult); return vecResult; } inline const Vector& CCollisionProperty::CollisionToWorldSpace(const Vector& in, Vector* pResult) const { if (!IsBoundsDefinedInEntitySpace() || (GetCollisionAngles() == vec3_angle)) { VectorAdd(in, GetCollisionOrigin(), *pResult); } else { VectorTransform(in, CollisionToWorldTransform(), *pResult); } return *pResult; } 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; } 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; } inline void CCollisionProperty::WorldSpaceAABB(Vector* pWorldMins, Vector* pWorldMaxs) const { CollisionAABBToWorldAABB(m_vecMins, m_vecMaxs, pWorldMins, pWorldMaxs); } inline const Vector& CCollisionProperty::CollisionSpaceMins(void) const { return m_vecMins; } inline const Vector& CCollisionProperty::CollisionSpaceMaxs(void) const { return m_vecMaxs; } 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(); 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