Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef COLLISIONPROPERTY_H
  8. #define COLLISIONPROPERTY_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "networkvar.h"
  13. #include "engine/ICollideable.h"
  14. #include "mathlib/vector.h"
  15. #include "ispatialpartition.h"
  16. //-----------------------------------------------------------------------------
  17. // Forward declarations
  18. //-----------------------------------------------------------------------------
  19. class CBaseEntity;
  20. class IHandleEntity;
  21. class QAngle;
  22. class Vector;
  23. struct Ray_t;
  24. class IPhysicsObject;
  25. //-----------------------------------------------------------------------------
  26. // Force spatial partition updates (to avoid threading problems caused by lazy update)
  27. //-----------------------------------------------------------------------------
  28. void UpdateDirtySpatialPartitionEntities();
  29. //-----------------------------------------------------------------------------
  30. // Specifies how to compute the surrounding box
  31. //-----------------------------------------------------------------------------
  32. enum SurroundingBoundsType_t
  33. {
  34. USE_OBB_COLLISION_BOUNDS = 0,
  35. USE_BEST_COLLISION_BOUNDS, // Always use the best bounds (most expensive)
  36. USE_HITBOXES,
  37. USE_SPECIFIED_BOUNDS,
  38. USE_GAME_CODE,
  39. USE_ROTATION_EXPANDED_BOUNDS,
  40. USE_COLLISION_BOUNDS_NEVER_VPHYSICS,
  41. SURROUNDING_TYPE_BIT_COUNT = 3
  42. };
  43. //-----------------------------------------------------------------------------
  44. // Encapsulates collision representation for an entity
  45. //-----------------------------------------------------------------------------
  46. class CCollisionProperty : public ICollideable
  47. {
  48. DECLARE_CLASS_NOBASE( CCollisionProperty );
  49. DECLARE_EMBEDDED_NETWORKVAR();
  50. DECLARE_PREDICTABLE();
  51. #ifdef GAME_DLL
  52. DECLARE_DATADESC();
  53. #endif
  54. public:
  55. CCollisionProperty();
  56. ~CCollisionProperty();
  57. void Init( CBaseEntity *pEntity );
  58. // Methods of ICollideable
  59. virtual IHandleEntity *GetEntityHandle();
  60. virtual const Vector& OBBMinsPreScaled() const { return m_vecMinsPreScaled.Get(); }
  61. virtual const Vector& OBBMaxsPreScaled() const { return m_vecMaxsPreScaled.Get(); }
  62. virtual const Vector& OBBMins() const { return m_vecMins.Get(); }
  63. virtual const Vector& OBBMaxs() const { return m_vecMaxs.Get(); }
  64. virtual void WorldSpaceTriggerBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) const;
  65. virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
  66. virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
  67. virtual int GetCollisionModelIndex();
  68. virtual const model_t* GetCollisionModel();
  69. virtual const Vector& GetCollisionOrigin() const;
  70. virtual const QAngle& GetCollisionAngles() const;
  71. virtual const matrix3x4_t& CollisionToWorldTransform() const;
  72. virtual SolidType_t GetSolid() const;
  73. virtual int GetSolidFlags() const;
  74. virtual IClientUnknown* GetIClientUnknown();
  75. virtual int GetCollisionGroup() const;
  76. virtual void WorldSpaceSurroundingBounds( Vector *pVecMins, Vector *pVecMaxs );
  77. virtual bool ShouldTouchTrigger( int triggerSolidFlags ) const;
  78. virtual const matrix3x4_t *GetRootParentToWorldTransform() const;
  79. public:
  80. // Spatial partition management
  81. void CreatePartitionHandle();
  82. void DestroyPartitionHandle();
  83. unsigned short GetPartitionHandle() const;
  84. // Marks the spatial partition dirty
  85. void MarkPartitionHandleDirty();
  86. // Sets the collision bounds + the size (OBB)
  87. void SetCollisionBounds( const Vector& mins, const Vector &maxs );
  88. // Rebuilds the scaled bounds from the pre-scaled bounds after a model's scale has changed
  89. void RefreshScaledCollisionBounds( void );
  90. // Sets special trigger bounds. The bloat amount indicates how much bigger the
  91. // trigger bounds should be beyond the bounds set in SetCollisionBounds
  92. // This method will also set the FSOLID flag FSOLID_USE_TRIGGER_BOUNDS
  93. void UseTriggerBounds( bool bEnable, float flBloat = 0.0f );
  94. // Sets the method by which the surrounding collision bounds is set
  95. // You must pass in values for mins + maxs if you select the USE_SPECIFIED_BOUNDS type.
  96. void SetSurroundingBoundsType( SurroundingBoundsType_t type, const Vector *pMins = NULL, const Vector *pMaxs = NULL );
  97. // Sets the solid type (which type of collision representation)
  98. void SetSolid( SolidType_t val );
  99. // Methods related to size. The OBB here is measured in CollisionSpace
  100. // (specified by GetCollisionToWorld)
  101. const Vector& OBBSize( ) const;
  102. // Returns a radius (or the square of the radius) of a sphere
  103. // *centered at the world space center* bounding the collision representation
  104. // of the entity. NOTE: The world space center *may* move when the entity rotates.
  105. float BoundingRadius() const;
  106. float BoundingRadius2D() const;
  107. // Returns the center of the OBB in collision space
  108. const Vector & OBBCenter( ) const;
  109. // center point of entity measured in world space
  110. // NOTE: This point *may* move when the entity moves depending on
  111. // which solid type is being used.
  112. const Vector & WorldSpaceCenter( ) const;
  113. // Methods related to solid flags
  114. void ClearSolidFlags( void );
  115. void RemoveSolidFlags( int flags );
  116. void AddSolidFlags( int flags );
  117. bool IsSolidFlagSet( int flagMask ) const;
  118. void SetSolidFlags( int flags );
  119. bool IsSolid() const;
  120. // Updates the spatial partition
  121. void UpdatePartition( );
  122. // Are the bounds defined in entity space?
  123. bool IsBoundsDefinedInEntitySpace() const;
  124. // Transforms a point in OBB space to world space
  125. const Vector & CollisionToWorldSpace( const Vector &in, Vector *pResult ) const;
  126. // Transforms a point in world space to OBB space
  127. const Vector & WorldToCollisionSpace( const Vector &in, Vector *pResult ) const;
  128. // Transforms a direction in world space to OBB space
  129. const Vector & WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const;
  130. // Selects a random point in the bounds given the normalized 0-1 bounds
  131. void RandomPointInBounds( const Vector &vecNormalizedMins, const Vector &vecNormalizedMaxs, Vector *pPoint) const;
  132. // Is a worldspace point within the bounds of the OBB?
  133. bool IsPointInBounds( const Vector &vecWorldPt ) const;
  134. // Computes a bounding box in world space surrounding the collision bounds
  135. void WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const;
  136. // Get the collision space mins directly
  137. const Vector & CollisionSpaceMins( void ) const;
  138. // Get the collision space maxs directly
  139. const Vector & CollisionSpaceMaxs( void ) const;
  140. // Computes a "normalized" point (range 0,0,0 - 1,1,1) in collision space
  141. // Useful for things like getting a point 75% of the way along z on the OBB, for example
  142. const Vector & NormalizedToCollisionSpace( const Vector &in, Vector *pResult ) const;
  143. // Computes a "normalized" point (range 0,0,0 - 1,1,1) in world space
  144. const Vector & NormalizedToWorldSpace( const Vector &in, Vector *pResult ) const;
  145. // Transforms a point in world space to normalized space
  146. const Vector & WorldToNormalizedSpace( const Vector &in, Vector *pResult ) const;
  147. // Transforms a point in collision space to normalized space
  148. const Vector & CollisionToNormalizedSpace( const Vector &in, Vector *pResult ) const;
  149. // Computes the nearest point in the OBB to a point specified in world space
  150. void CalcNearestPoint( const Vector &vecWorldPt, Vector *pVecNearestWorldPt ) const;
  151. // Computes the distance from a point in world space to the OBB
  152. float CalcDistanceFromPoint( const Vector &vecWorldPt ) const;
  153. // Does a rotation make us need to recompute the surrounding box?
  154. bool DoesRotationInvalidateSurroundingBox( ) const;
  155. // Does VPhysicsUpdate make us need to recompute the surrounding box?
  156. bool DoesVPhysicsInvalidateSurroundingBox( ) const;
  157. // Marks the entity has having a dirty surrounding box
  158. void MarkSurroundingBoundsDirty();
  159. // Compute the largest dot product of the OBB and the specified direction vector
  160. float ComputeSupportMap( const Vector &vecDirection ) const;
  161. private:
  162. // Transforms an AABB measured in collision space to a box that surrounds it in world space
  163. void CollisionAABBToWorldAABB( const Vector &entityMins, const Vector &entityMaxs, Vector *pWorldMins, Vector *pWorldMaxs ) const;
  164. // Expand trigger bounds..
  165. void ComputeVPhysicsSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
  166. // Expand trigger bounds..
  167. bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
  168. bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
  169. // Computes the surrounding collision bounds based on whatever algorithm we want...
  170. void ComputeCollisionSurroundingBox( bool bUseVPhysics, Vector *pVecWorldMins, Vector *pVecWorldMaxs );
  171. // Computes the surrounding collision bounds from the the OBB (not vphysics)
  172. void ComputeRotationExpandedBounds( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
  173. // Computes the surrounding collision bounds based on whatever algorithm we want...
  174. void ComputeSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
  175. // Check for untouch
  176. void CheckForUntouch();
  177. // Updates the spatial partition
  178. void UpdateServerPartitionMask( );
  179. // Outer
  180. CBaseEntity *GetOuter();
  181. const CBaseEntity *GetOuter() const;
  182. private:
  183. CBaseEntity *m_pOuter;
  184. CNetworkVector( m_vecMinsPreScaled );
  185. CNetworkVector( m_vecMaxsPreScaled );
  186. CNetworkVector( m_vecMins );
  187. CNetworkVector( m_vecMaxs );
  188. float m_flRadius;
  189. CNetworkVar( unsigned short, m_usSolidFlags );
  190. // Spatial partition
  191. SpatialPartitionHandle_t m_Partition;
  192. CNetworkVar( unsigned char, m_nSurroundType );
  193. // One of the SOLID_ defines. Use GetSolid/SetSolid.
  194. CNetworkVar( unsigned char, m_nSolidType );
  195. CNetworkVar( unsigned char , m_triggerBloat );
  196. // SUCKY: We didn't use to have to store this previously
  197. // but storing it here means that we can network it + avoid a ton of
  198. // client-side mismatch problems
  199. CNetworkVector( m_vecSpecifiedSurroundingMinsPreScaled );
  200. CNetworkVector( m_vecSpecifiedSurroundingMaxsPreScaled );
  201. CNetworkVector( m_vecSpecifiedSurroundingMins );
  202. CNetworkVector( m_vecSpecifiedSurroundingMaxs );
  203. // Cached off world-aligned surrounding bounds
  204. #if 0
  205. short m_surroundingMins[3];
  206. short m_surroundingMaxs[3];
  207. #else
  208. Vector m_vecSurroundingMins;
  209. Vector m_vecSurroundingMaxs;
  210. #endif
  211. // pointer to the entity's physics object (vphysics.dll)
  212. //IPhysicsObject *m_pPhysicsObject;
  213. friend class CBaseEntity;
  214. };
  215. //-----------------------------------------------------------------------------
  216. // For networking this bad boy
  217. //-----------------------------------------------------------------------------
  218. #ifdef CLIENT_DLL
  219. EXTERN_RECV_TABLE( DT_CollisionProperty );
  220. #else
  221. EXTERN_SEND_TABLE( DT_CollisionProperty );
  222. #endif
  223. //-----------------------------------------------------------------------------
  224. // Inline methods
  225. //-----------------------------------------------------------------------------
  226. inline CBaseEntity *CCollisionProperty::GetOuter()
  227. {
  228. return m_pOuter;
  229. }
  230. inline const CBaseEntity *CCollisionProperty::GetOuter() const
  231. {
  232. return m_pOuter;
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Spatial partition
  236. //-----------------------------------------------------------------------------
  237. inline unsigned short CCollisionProperty::GetPartitionHandle() const
  238. {
  239. return m_Partition;
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Methods related to size
  243. //-----------------------------------------------------------------------------
  244. inline const Vector& CCollisionProperty::OBBSize( ) const
  245. {
  246. // NOTE: Could precache this, but it's not used that often..
  247. Vector &temp = AllocTempVector();
  248. VectorSubtract( m_vecMaxs, m_vecMins, temp );
  249. return temp;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Bounding radius size
  253. //-----------------------------------------------------------------------------
  254. inline float CCollisionProperty::BoundingRadius() const
  255. {
  256. return m_flRadius;
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Methods relating to solid flags
  260. //-----------------------------------------------------------------------------
  261. inline bool CCollisionProperty::IsBoundsDefinedInEntitySpace() const
  262. {
  263. return (( m_usSolidFlags & FSOLID_FORCE_WORLD_ALIGNED ) == 0 ) &&
  264. ( m_nSolidType != SOLID_BBOX ) && ( m_nSolidType != SOLID_NONE );
  265. }
  266. inline void CCollisionProperty::ClearSolidFlags( void )
  267. {
  268. SetSolidFlags( 0 );
  269. }
  270. inline void CCollisionProperty::RemoveSolidFlags( int flags )
  271. {
  272. SetSolidFlags( m_usSolidFlags & ~flags );
  273. }
  274. inline void CCollisionProperty::AddSolidFlags( int flags )
  275. {
  276. SetSolidFlags( m_usSolidFlags | flags );
  277. }
  278. inline int CCollisionProperty::GetSolidFlags( void ) const
  279. {
  280. return m_usSolidFlags;
  281. }
  282. inline bool CCollisionProperty::IsSolidFlagSet( int flagMask ) const
  283. {
  284. return (m_usSolidFlags & flagMask) != 0;
  285. }
  286. inline bool CCollisionProperty::IsSolid() const
  287. {
  288. return ::IsSolid( (SolidType_t)(unsigned char)m_nSolidType, m_usSolidFlags );
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Returns the center in OBB space
  292. //-----------------------------------------------------------------------------
  293. inline const Vector& CCollisionProperty::OBBCenter( ) const
  294. {
  295. Vector &vecResult = AllocTempVector();
  296. VectorLerp( m_vecMins, m_vecMaxs, 0.5f, vecResult );
  297. return vecResult;
  298. }
  299. //-----------------------------------------------------------------------------
  300. // center point of entity
  301. //-----------------------------------------------------------------------------
  302. inline const Vector &CCollisionProperty::WorldSpaceCenter( ) const
  303. {
  304. Vector &vecResult = AllocTempVector();
  305. CollisionToWorldSpace( OBBCenter(), &vecResult );
  306. return vecResult;
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Transforms a point in OBB space to world space
  310. //-----------------------------------------------------------------------------
  311. inline const Vector &CCollisionProperty::CollisionToWorldSpace( const Vector &in, Vector *pResult ) const
  312. {
  313. // Makes sure we don't re-use the same temp twice
  314. if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) )
  315. {
  316. VectorAdd( in, GetCollisionOrigin(), *pResult );
  317. }
  318. else
  319. {
  320. VectorTransform( in, CollisionToWorldTransform(), *pResult );
  321. }
  322. return *pResult;
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Transforms a point in world space to OBB space
  326. //-----------------------------------------------------------------------------
  327. inline const Vector &CCollisionProperty::WorldToCollisionSpace( const Vector &in, Vector *pResult ) const
  328. {
  329. if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) )
  330. {
  331. VectorSubtract( in, GetCollisionOrigin(), *pResult );
  332. }
  333. else
  334. {
  335. VectorITransform( in, CollisionToWorldTransform(), *pResult );
  336. }
  337. return *pResult;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Transforms a direction in world space to OBB space
  341. //-----------------------------------------------------------------------------
  342. inline const Vector & CCollisionProperty::WorldDirectionToCollisionSpace( const Vector &in, Vector *pResult ) const
  343. {
  344. if ( !IsBoundsDefinedInEntitySpace() || ( GetCollisionAngles() == vec3_angle ) )
  345. {
  346. *pResult = in;
  347. }
  348. else
  349. {
  350. VectorIRotate( in, CollisionToWorldTransform(), *pResult );
  351. }
  352. return *pResult;
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Computes a bounding box in world space surrounding the collision bounds
  356. //-----------------------------------------------------------------------------
  357. inline void CCollisionProperty::WorldSpaceAABB( Vector *pWorldMins, Vector *pWorldMaxs ) const
  358. {
  359. CollisionAABBToWorldAABB( m_vecMins, m_vecMaxs, pWorldMins, pWorldMaxs );
  360. }
  361. // Get the collision space mins directly
  362. inline const Vector & CCollisionProperty::CollisionSpaceMins( void ) const
  363. {
  364. return m_vecMins;
  365. }
  366. // Get the collision space maxs directly
  367. inline const Vector & CCollisionProperty::CollisionSpaceMaxs( void ) const
  368. {
  369. return m_vecMaxs;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Does a rotation make us need to recompute the surrounding box?
  373. //-----------------------------------------------------------------------------
  374. inline bool CCollisionProperty::DoesRotationInvalidateSurroundingBox( ) const
  375. {
  376. if ( IsSolidFlagSet(FSOLID_ROOT_PARENT_ALIGNED) )
  377. return true;
  378. switch ( m_nSurroundType )
  379. {
  380. case USE_COLLISION_BOUNDS_NEVER_VPHYSICS:
  381. case USE_OBB_COLLISION_BOUNDS:
  382. case USE_BEST_COLLISION_BOUNDS:
  383. return IsBoundsDefinedInEntitySpace();
  384. // In the case of game code, we don't really know, so we have to assume it does
  385. case USE_HITBOXES:
  386. case USE_GAME_CODE:
  387. return true;
  388. case USE_ROTATION_EXPANDED_BOUNDS:
  389. case USE_SPECIFIED_BOUNDS:
  390. return false;
  391. default:
  392. Assert(0);
  393. return true;
  394. }
  395. }
  396. #endif // COLLISIONPROPERTY_H