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.

1932 lines
57 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "ivp_surbuild_pointsoup.hxx"
  10. #include "ivp_surbuild_ledge_soup.hxx"
  11. #include "ivp_surman_polygon.hxx"
  12. #include "ivp_compact_surface.hxx"
  13. #include "ivp_compact_ledge.hxx"
  14. #include "ivp_compact_ledge_solver.hxx"
  15. #include "ivp_halfspacesoup.hxx"
  16. #include "ivp_surbuild_halfspacesoup.hxx"
  17. #include "ivp_template_surbuild.hxx"
  18. #include "hk_mopp/ivp_surbuild_mopp.hxx"
  19. #include "hk_mopp/ivp_surman_mopp.hxx"
  20. #include "hk_mopp/ivp_compact_mopp.hxx"
  21. #include "ivp_surbuild_polygon_convex.hxx"
  22. #include "ivp_templates_intern.hxx"
  23. #include "cmodel.h"
  24. #include "physics_trace.h"
  25. #include "vcollide_parse_private.h"
  26. #include "physics_virtualmesh.h"
  27. #include "mathlib/polyhedron.h"
  28. #include "tier1/byteswap.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. class CPhysCollideCompactSurface;
  32. struct bboxcache_t
  33. {
  34. Vector mins;
  35. Vector maxs;
  36. CPhysCollideCompactSurface *pCollide;
  37. };
  38. class CPhysicsCollision : public IPhysicsCollision
  39. {
  40. public:
  41. CPhysicsCollision()
  42. {
  43. }
  44. CPhysConvex *ConvexFromVerts( Vector **pVerts, int vertCount );
  45. CPhysConvex *ConvexFromVertsFast( Vector **pVerts, int vertCount );
  46. CPhysConvex *ConvexFromPlanes( float *pPlanes, int planeCount, float mergeDistance );
  47. CPhysConvex *ConvexFromConvexPolyhedron( const CPolyhedron &ConvexPolyhedron );
  48. void ConvexesFromConvexPolygon( const Vector &vPolyNormal, const Vector *pPoints, int iPointCount, CPhysConvex **pOutput );
  49. CPhysConvex *RebuildConvexFromPlanes( CPhysConvex *pConvex, float mergeDistance );
  50. float ConvexVolume( CPhysConvex *pConvex );
  51. float ConvexSurfaceArea( CPhysConvex *pConvex );
  52. CPhysCollide *ConvertConvexToCollide( CPhysConvex **pConvex, int convexCount );
  53. CPhysCollide *ConvertConvexToCollideParams( CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams );
  54. CPolyhedron *PolyhedronFromConvex( CPhysConvex * const pConvex, bool bUseTempPolyhedron );
  55. int GetConvexesUsedInCollideable( const CPhysCollide *pCollideable, CPhysConvex **pOutputArray, int iOutputArrayLimit );
  56. // store game-specific data in a convex solid
  57. void SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData );
  58. void ConvexFree( CPhysConvex *pConvex );
  59. CPhysPolysoup *PolysoupCreate( void );
  60. void PolysoupDestroy( CPhysPolysoup *pSoup );
  61. void PolysoupAddTriangle( CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits );
  62. CPhysCollide *ConvertPolysoupToCollide( CPhysPolysoup *pSoup, bool useMOPP = true );
  63. int CollideSize( CPhysCollide *pCollide );
  64. int CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap = false );
  65. // Get the AABB of an oriented collide
  66. virtual void CollideGetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles );
  67. virtual Vector CollideGetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction );
  68. // compute the volume of a collide
  69. virtual float CollideVolume( CPhysCollide *pCollide );
  70. virtual float CollideSurfaceArea( CPhysCollide *pCollide );
  71. // Free a collide that was created with ConvertConvexToCollide()
  72. // UNDONE: Move this up near the other Collide routines when the version is changed
  73. virtual void DestroyCollide( CPhysCollide *pCollide );
  74. CPhysCollide *BBoxToCollide( const Vector &mins, const Vector &maxs );
  75. CPhysConvex *BBoxToConvex( const Vector &mins, const Vector &maxs );
  76. // loads a set of solids into a vcollide_t
  77. virtual void VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap );
  78. // destroyts the set of solids created by VCollideLoad
  79. virtual void VCollideUnload( vcollide_t *pVCollide );
  80. // Trace an AABB against a collide
  81. void TraceBox( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr );
  82. void TraceBox( const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr );
  83. void TraceBox( const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr );
  84. // Trace one collide against another
  85. void TraceCollide( const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr );
  86. bool IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone );
  87. // begins parsing a vcollide. NOTE: This keeps pointers to the text
  88. // If you delete the text and call members of IVPhysicsKeyParser, it will crash
  89. virtual IVPhysicsKeyParser *VPhysicsKeyParserCreate( const char *pKeyData );
  90. // Free the parser created by VPhysicsKeyParserCreate
  91. virtual void VPhysicsKeyParserDestroy( IVPhysicsKeyParser *pParser );
  92. // creates a list of verts from a collision mesh
  93. int CreateDebugMesh( const CPhysCollide *pCollisionModel, Vector **outVerts );
  94. // destroy the list of verts created by CreateDebugMesh
  95. void DestroyDebugMesh( int vertCount, Vector *outVerts );
  96. // create a queryable version of the collision model
  97. ICollisionQuery *CreateQueryModel( CPhysCollide *pCollide );
  98. // destroy the queryable version
  99. void DestroyQueryModel( ICollisionQuery *pQuery );
  100. virtual IPhysicsCollision *ThreadContextCreate( void );
  101. virtual void ThreadContextDestroy( IPhysicsCollision *pThreadContex );
  102. virtual unsigned int ReadStat( int statID ) { return 0; }
  103. virtual void CollideGetMassCenter( CPhysCollide *pCollide, Vector *pOutMassCenter );
  104. virtual void CollideSetMassCenter( CPhysCollide *pCollide, const Vector &massCenter );
  105. virtual int CollideIndex( const CPhysCollide *pCollide );
  106. virtual Vector CollideGetOrthographicAreas( const CPhysCollide *pCollide );
  107. virtual void OutputDebugInfo( const CPhysCollide *pCollide );
  108. virtual CPhysCollide *CreateVirtualMesh(const virtualmeshparams_t &params) { return ::CreateVirtualMesh(params); }
  109. virtual bool GetBBoxCacheSize( int *pCachedSize, int *pCachedCount );
  110. virtual bool SupportsVirtualMesh() { return true; }
  111. virtual CPhysCollide *UnserializeCollide( char *pBuffer, int size, int index );
  112. virtual void CollideSetOrthographicAreas( CPhysCollide *pCollide, const Vector &areas );
  113. private:
  114. void InitBBoxCache();
  115. bool IsBBoxCache( CPhysCollide *pCollide );
  116. void AddBBoxCache( CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs );
  117. CPhysCollideCompactSurface *GetBBoxCache( const Vector &mins, const Vector &maxs );
  118. CPhysCollideCompactSurface *FastBboxCollide( const CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs );
  119. private:
  120. CPhysicsTrace m_traceapi;
  121. CUtlVector<bboxcache_t> m_bboxCache;
  122. byte m_bboxVertMap[8];
  123. };
  124. CPhysicsCollision g_PhysicsCollision;
  125. IPhysicsCollision *physcollision = &g_PhysicsCollision;
  126. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CPhysicsCollision, IPhysicsCollision, VPHYSICS_COLLISION_INTERFACE_VERSION, g_PhysicsCollision );
  127. //-----------------------------------------------------------------------------
  128. // Abstract compact_surface vs. compact_mopp
  129. //-----------------------------------------------------------------------------
  130. #define IVP_COMPACT_SURFACE_ID MAKEID('I','V','P','S')
  131. #define IVP_COMPACT_SURFACE_ID_SWAPPED MAKEID('S','P','V','I')
  132. #define IVP_COMPACT_MOPP_ID MAKEID('M','O','P','P')
  133. #define VPHYSICS_COLLISION_ID MAKEID('V','P','H','Y')
  134. #define VPHYSICS_COLLISION_VERSION 0x0100
  135. // You can disable all of the havok Mopp collision model building by undefining this symbol
  136. #define ENABLE_IVP_MOPP 0
  137. struct physcollideheader_t
  138. {
  139. DECLARE_BYTESWAP_DATADESC();
  140. int vphysicsID;
  141. short version;
  142. short modelType;
  143. void Defaults( short inputModelType )
  144. {
  145. vphysicsID = VPHYSICS_COLLISION_ID;
  146. version = VPHYSICS_COLLISION_VERSION;
  147. modelType = inputModelType;
  148. }
  149. };
  150. struct compactsurfaceheader_t : public physcollideheader_t
  151. {
  152. DECLARE_BYTESWAP_DATADESC();
  153. int surfaceSize;
  154. Vector dragAxisAreas;
  155. int axisMapSize;
  156. void CompactSurface( const IVP_Compact_Surface *pSurface, const Vector &orthoAreas )
  157. {
  158. Defaults( COLLIDE_POLY );
  159. surfaceSize = pSurface->byte_size;
  160. dragAxisAreas = orthoAreas;
  161. axisMapSize = 0; // NOTE: not yet supported
  162. }
  163. };
  164. BEGIN_BYTESWAP_DATADESC( physcollideheader_t )
  165. DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
  166. DEFINE_FIELD( version, FIELD_SHORT),
  167. DEFINE_FIELD( modelType, FIELD_SHORT ),
  168. END_BYTESWAP_DATADESC()
  169. BEGIN_BYTESWAP_DATADESC_( compactsurfaceheader_t, physcollideheader_t )
  170. DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
  171. DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
  172. DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
  173. END_BYTESWAP_DATADESC()
  174. #if ENABLE_IVP_MOPP
  175. struct moppheader_t : public physcollideheader_t
  176. {
  177. int moppSize;
  178. void Mopp( const IVP_Compact_Mopp *pMopp )
  179. {
  180. Defaults( COLLIDE_MOPP );
  181. moppSize = pMopp->byte_size;
  182. }
  183. };
  184. #endif
  185. #if ENABLE_IVP_MOPP
  186. class CPhysCollideMopp : public CPhysCollide
  187. {
  188. public:
  189. CPhysCollideMopp( const moppheader_t *pHeader );
  190. CPhysCollideMopp( IVP_Compact_Mopp *pMopp );
  191. CPhysCollideMopp( const char *pBuffer, unsigned int size );
  192. ~CPhysCollideMopp();
  193. void Init( const char *pBuffer, unsigned int size );
  194. // IPhysCollide
  195. virtual int GetVCollideIndex() const { return 0; }
  196. virtual IVP_SurfaceManager *CreateSurfaceManager( short & ) const;
  197. virtual void GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const;
  198. virtual unsigned int GetSerializationSize() const;
  199. virtual Vector GetMassCenter() const;
  200. virtual void SetMassCenter( const Vector &massCenter );
  201. virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const;
  202. virtual void OutputDebugInfo() const;
  203. private:
  204. IVP_Compact_Mopp *m_pMopp;
  205. };
  206. #endif
  207. class CPhysCollideCompactSurface : public CPhysCollide
  208. {
  209. public:
  210. ~CPhysCollideCompactSurface();
  211. CPhysCollideCompactSurface( const char *pBuffer, unsigned int size, int index, bool swap = false );
  212. CPhysCollideCompactSurface( const compactsurfaceheader_t *pHeader, int index, bool swap = false );
  213. CPhysCollideCompactSurface( IVP_Compact_Surface *pSurface );
  214. void Init( const char *pBuffer, unsigned int size, int index, bool swap = false );
  215. // IPhysCollide
  216. virtual int GetVCollideIndex() const { return m_pCompactSurface->dummy[0]; }
  217. virtual IVP_SurfaceManager *CreateSurfaceManager( short & ) const;
  218. virtual void GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const;
  219. virtual unsigned int GetSerializationSize() const;
  220. virtual Vector GetMassCenter() const;
  221. virtual void SetMassCenter( const Vector &massCenter );
  222. virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const;
  223. virtual Vector GetOrthographicAreas() const;
  224. void SetOrthographicAreas( const Vector &areas );
  225. virtual void ComputeOrthographicAreas( float epsilon );
  226. virtual void OutputDebugInfo() const;
  227. const IVP_Compact_Surface *GetCompactSurface() const { return m_pCompactSurface; }
  228. virtual const collidemap_t *GetCollideMap() const { return m_pCollideMap; }
  229. private:
  230. struct hullinfo_t
  231. {
  232. hullinfo_t()
  233. {
  234. hasOuterHull = false;
  235. convexCount = 0;
  236. }
  237. bool hasOuterHull;
  238. int convexCount;
  239. };
  240. void ComputeHullInfo_r( hullinfo_t *pOut, const IVP_Compact_Ledgetree_Node *node ) const;
  241. void InitCollideMap();
  242. IVP_Compact_Surface *m_pCompactSurface;
  243. Vector m_orthoAreas;
  244. collidemap_t *m_pCollideMap;
  245. };
  246. static const IVP_Compact_Surface *ConvertPhysCollideToCompactSurface( const CPhysCollide *pCollide )
  247. {
  248. return pCollide->GetCompactSurface();
  249. }
  250. IVP_SurfaceManager *CreateSurfaceManager( const CPhysCollide *pCollisionModel, short &collideType )
  251. {
  252. return pCollisionModel ? pCollisionModel->CreateSurfaceManager( collideType ) : NULL;
  253. }
  254. void OutputCollideDebugInfo( const CPhysCollide *pCollisionModel )
  255. {
  256. pCollisionModel->OutputDebugInfo();
  257. }
  258. CPhysCollide *CPhysCollide::UnserializeFromBuffer( const char *pBuffer, unsigned int size, int index, bool swap )
  259. {
  260. const physcollideheader_t *pHeader = reinterpret_cast<const physcollideheader_t *>(pBuffer);
  261. if ( pHeader->vphysicsID == VPHYSICS_COLLISION_ID )
  262. {
  263. Assert(pHeader->version == VPHYSICS_COLLISION_VERSION);
  264. switch( pHeader->modelType )
  265. {
  266. case COLLIDE_POLY:
  267. return new CPhysCollideCompactSurface( (compactsurfaceheader_t *)pHeader, index, swap );
  268. case COLLIDE_MOPP:
  269. #if ENABLE_IVP_MOPP
  270. return new CPhysCollideMopp( (moppheader_t *)pHeader );
  271. #else
  272. DevMsg( 2, "Null physics model\n");
  273. return NULL;
  274. #endif
  275. default:
  276. Assert(0);
  277. return NULL;
  278. }
  279. }
  280. const IVP_Compact_Surface *pSurface = reinterpret_cast<const IVP_Compact_Surface *>(pBuffer);
  281. if ( pSurface->dummy[2] == IVP_COMPACT_MOPP_ID )
  282. {
  283. #if ENABLE_IVP_MOPP
  284. return new CPhysCollideMopp( pBuffer, size );
  285. #else
  286. Assert(0);
  287. return NULL;
  288. #endif
  289. }
  290. if ( pSurface->dummy[2] == IVP_COMPACT_SURFACE_ID ||
  291. pSurface->dummy[2] == IVP_COMPACT_SURFACE_ID_SWAPPED ||
  292. pSurface->dummy[2] == 0 )
  293. {
  294. if ( pSurface->dummy[2] == 0 )
  295. {
  296. // UNDONE: Print a name here?
  297. DevMsg( 1, "Old format .PHY file loaded!!!\n" );
  298. }
  299. return new CPhysCollideCompactSurface( pBuffer, size, index, swap );
  300. }
  301. Assert(0);
  302. return NULL;
  303. }
  304. #if ENABLE_IVP_MOPP
  305. void CPhysCollideMopp::Init( const char *pBuffer, unsigned int size )
  306. {
  307. m_pMopp = (IVP_Compact_Mopp *)ivp_malloc_aligned( size, 32 );
  308. memcpy( m_pMopp, pBuffer, size );
  309. }
  310. CPhysCollideMopp::CPhysCollideMopp( const char *pBuffer, unsigned int size )
  311. {
  312. Init( pBuffer, size );
  313. }
  314. CPhysCollideMopp::CPhysCollideMopp( const moppheader_t *pHeader )
  315. {
  316. Init( (const char *)(pHeader+1), pHeader->moppSize );
  317. }
  318. CPhysCollideMopp::CPhysCollideMopp( IVP_Compact_Mopp *pMopp )
  319. {
  320. m_pMopp = pMopp;
  321. pMopp->dummy = IVP_COMPACT_MOPP_ID;
  322. }
  323. CPhysCollideMopp::~CPhysCollideMopp()
  324. {
  325. ivp_free_aligned(m_pMopp);
  326. }
  327. void CPhysCollideMopp::GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const
  328. {
  329. IVP_Compact_Ledge_Solver::get_all_ledges( m_pMopp, &ledges );
  330. }
  331. IVP_SurfaceManager *CPhysCollideMopp::CreateSurfaceManager( short &collideType ) const
  332. {
  333. collideType = COLLIDE_MOPP;
  334. return new IVP_SurfaceManager_Mopp( m_pMopp );
  335. }
  336. unsigned int CPhysCollideMopp::GetSerializationSize() const
  337. {
  338. return m_pMopp->byte_size + sizeof(moppheader_t);
  339. }
  340. unsigned int CPhysCollideMopp::SerializeToBuffer( char *pDest, bool bSwap ) const
  341. {
  342. moppheader_t header;
  343. header.Mopp( m_pMopp );
  344. memcpy( pDest, &header, sizeof(header) );
  345. pDest += sizeof(header);
  346. memcpy( pDest, m_pMopp, m_pMopp->byte_size );
  347. return GetSerializationSize();
  348. }
  349. Vector CPhysCollideMopp::GetMassCenter() const
  350. {
  351. Vector massCenterHL;
  352. ConvertPositionToHL( m_pMopp->mass_center, massCenterHL );
  353. return massCenterHL;
  354. }
  355. void CPhysCollideMopp::SetMassCenter( const Vector &massCenterHL )
  356. {
  357. ConvertPositionToIVP( massCenterHL, m_pMopp->mass_center );
  358. }
  359. void CPhysCollideMopp::OutputDebugInfo() const
  360. {
  361. Msg("CollisionModel: MOPP\n");
  362. }
  363. #endif
  364. void CPhysCollideCompactSurface::InitCollideMap()
  365. {
  366. m_pCollideMap = NULL;
  367. if ( m_pCompactSurface )
  368. {
  369. IVP_U_BigVector<IVP_Compact_Ledge> ledges;
  370. GetAllLedges( ledges );
  371. // don't make these for really large models because there's a linear search involved in using this atm.
  372. if ( !ledges.len() || ledges.len() > 32 )
  373. return;
  374. int allocSize = sizeof(collidemap_t) + ((ledges.len()-1) * sizeof(leafmap_t));
  375. m_pCollideMap = (collidemap_t *)malloc(allocSize);
  376. m_pCollideMap->leafCount = ledges.len();
  377. for ( int i = 0; i < ledges.len(); i++ )
  378. {
  379. InitLeafmap( ledges.element_at(i), &m_pCollideMap->leafmap[i] );
  380. }
  381. }
  382. }
  383. void CPhysCollideCompactSurface::Init( const char *pBuffer, unsigned int size, int index, bool bSwap )
  384. {
  385. m_pCompactSurface = (IVP_Compact_Surface *)ivp_malloc_aligned( size, 32 );
  386. memcpy( m_pCompactSurface, pBuffer, size );
  387. if ( bSwap )
  388. {
  389. m_pCompactSurface->byte_swap_all();
  390. }
  391. m_pCompactSurface->dummy[0] = index;
  392. m_orthoAreas.Init(1,1,1);
  393. InitCollideMap();
  394. }
  395. CPhysCollideCompactSurface::CPhysCollideCompactSurface( const char *pBuffer, unsigned int size, int index, bool swap )
  396. {
  397. Init( pBuffer, size, index, swap );
  398. }
  399. CPhysCollideCompactSurface::CPhysCollideCompactSurface( const compactsurfaceheader_t *pHeader, int index, bool swap )
  400. {
  401. Init( (const char *)(pHeader+1), pHeader->surfaceSize, index, swap );
  402. m_orthoAreas = pHeader->dragAxisAreas;
  403. }
  404. CPhysCollideCompactSurface::CPhysCollideCompactSurface( IVP_Compact_Surface *pSurface )
  405. {
  406. m_pCompactSurface = pSurface;
  407. pSurface->dummy[2] = IVP_COMPACT_SURFACE_ID;
  408. m_pCompactSurface->dummy[0] = 0;
  409. m_orthoAreas.Init(1,1,1);
  410. InitCollideMap();
  411. }
  412. CPhysCollideCompactSurface::~CPhysCollideCompactSurface()
  413. {
  414. ivp_free_aligned(m_pCompactSurface);
  415. if ( m_pCollideMap )
  416. {
  417. free(m_pCollideMap);
  418. }
  419. }
  420. IVP_SurfaceManager *CPhysCollideCompactSurface::CreateSurfaceManager( short &collideType ) const
  421. {
  422. collideType = COLLIDE_POLY;
  423. return new IVP_SurfaceManager_Polygon( m_pCompactSurface );
  424. }
  425. void CPhysCollideCompactSurface::GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const
  426. {
  427. IVP_Compact_Ledge_Solver::get_all_ledges( m_pCompactSurface, &ledges );
  428. }
  429. unsigned int CPhysCollideCompactSurface::GetSerializationSize() const
  430. {
  431. return m_pCompactSurface->byte_size + sizeof(compactsurfaceheader_t);
  432. }
  433. unsigned int CPhysCollideCompactSurface::SerializeToBuffer( char *pDest, bool bSwap ) const
  434. {
  435. compactsurfaceheader_t header;
  436. header.CompactSurface( m_pCompactSurface, m_orthoAreas );
  437. if ( bSwap )
  438. {
  439. CByteswap swap;
  440. swap.ActivateByteSwapping( true );
  441. swap.SwapFieldsToTargetEndian( &header );
  442. }
  443. memcpy( pDest, &header, sizeof(header) );
  444. pDest += sizeof(header);
  445. int surfaceSize = m_pCompactSurface->byte_size;
  446. int serializationSize = GetSerializationSize();
  447. if ( bSwap )
  448. {
  449. m_pCompactSurface->byte_swap_all();
  450. }
  451. memcpy( pDest, m_pCompactSurface, surfaceSize );
  452. return serializationSize;
  453. }
  454. Vector CPhysCollideCompactSurface::GetMassCenter() const
  455. {
  456. Vector massCenterHL;
  457. ConvertPositionToHL( m_pCompactSurface->mass_center, massCenterHL );
  458. return massCenterHL;
  459. }
  460. void CPhysCollideCompactSurface::SetMassCenter( const Vector &massCenterHL )
  461. {
  462. ConvertPositionToIVP( massCenterHL, m_pCompactSurface->mass_center );
  463. }
  464. Vector CPhysCollideCompactSurface::GetOrthographicAreas() const
  465. {
  466. return m_orthoAreas;
  467. }
  468. void CPhysCollideCompactSurface::SetOrthographicAreas( const Vector &areas )
  469. {
  470. m_orthoAreas = areas;
  471. }
  472. void CPhysCollideCompactSurface::ComputeOrthographicAreas( float epsilon )
  473. {
  474. Vector mins, maxs, areas;
  475. physcollision->CollideGetAABB( &mins, &maxs, this, vec3_origin, vec3_angle );
  476. float side = sqrt( epsilon );
  477. if ( side < 1e-4f )
  478. side = 1e-4f;
  479. Vector size = maxs-mins;
  480. m_orthoAreas.Init(1,1,1);
  481. trace_t tr;
  482. for ( int axis = 0; axis < 3; axis++ )
  483. {
  484. int u = (axis+1)%3;
  485. int v = (axis+2)%3;
  486. int hits = 0;
  487. int total = 0;
  488. float halfSide = side * 0.5;
  489. for ( float u0 = mins[u] + halfSide; u0 < maxs[u]; u0 += side )
  490. {
  491. for ( float v0 = mins[v] + halfSide; v0 < maxs[v]; v0 += side )
  492. {
  493. Vector start, end;
  494. start[axis] = mins[axis]-1;
  495. end[axis] = maxs[axis]+1;
  496. start[u] = u0;
  497. end[u] = u0;
  498. start[v] = v0;
  499. end[v] = v0;
  500. physcollision->TraceBox( start, end, vec3_origin, vec3_origin, this, vec3_origin, vec3_angle, &tr );
  501. if ( tr.DidHit() )
  502. {
  503. hits++;
  504. }
  505. total++;
  506. }
  507. }
  508. if ( total <= 0 )
  509. total = 1;
  510. m_orthoAreas[axis] = (float)hits / (float)total;
  511. }
  512. }
  513. void CPhysCollideCompactSurface::ComputeHullInfo_r( hullinfo_t *pOut, const IVP_Compact_Ledgetree_Node *node ) const
  514. {
  515. if ( !node->is_terminal() )
  516. {
  517. if ( node->get_compact_hull() )
  518. pOut->hasOuterHull = true;
  519. ComputeHullInfo_r( pOut, node->left_son() );
  520. ComputeHullInfo_r( pOut, node->right_son() );
  521. }
  522. else
  523. {
  524. // terminal node, add one ledge
  525. pOut->convexCount++;
  526. }
  527. }
  528. void CPhysCollideCompactSurface::OutputDebugInfo() const
  529. {
  530. hullinfo_t info;
  531. ComputeHullInfo_r( &info, m_pCompactSurface->get_compact_ledge_tree_root() );
  532. const char *pOuterHull = info.hasOuterHull ? "with" : "no";
  533. Msg("CollisionModel: Compact Surface: %d convex pieces %s outer hull\n", info.convexCount, pOuterHull );
  534. }
  535. //-----------------------------------------------------------------------------
  536. //-----------------------------------------------------------------------------
  537. // Purpose: Create a convex element from a point cloud
  538. // Input : **pVerts - array of points
  539. // vertCount - length of array
  540. // Output : opaque pointer to convex element
  541. //-----------------------------------------------------------------------------
  542. CPhysConvex *CPhysicsCollision::ConvexFromVertsFast( Vector **pVerts, int vertCount )
  543. {
  544. IVP_U_Vector<IVP_U_Point> points;
  545. int i;
  546. for ( i = 0; i < vertCount; i++ )
  547. {
  548. IVP_U_Point *tmp = new IVP_U_Point;
  549. ConvertPositionToIVP( *pVerts[i], *tmp );
  550. BEGIN_IVP_ALLOCATION();
  551. points.add( tmp );
  552. END_IVP_ALLOCATION();
  553. }
  554. BEGIN_IVP_ALLOCATION();
  555. IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Pointsoup::convert_pointsoup_to_compact_ledge( &points );
  556. END_IVP_ALLOCATION();
  557. for ( i = 0; i < points.len(); i++ )
  558. {
  559. delete points.element_at(i);
  560. }
  561. points.clear();
  562. return reinterpret_cast<CPhysConvex *>(pLedge);
  563. }
  564. CPhysConvex *CPhysicsCollision::RebuildConvexFromPlanes( CPhysConvex *pConvex, float mergeTolerance )
  565. {
  566. if ( !pConvex )
  567. return NULL;
  568. IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex;
  569. int triangleCount = pLedge->get_n_triangles();
  570. IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  571. IVP_U_Hesse plane;
  572. IVP_Halfspacesoup halfspaces;
  573. for ( int j = 0; j < triangleCount; j++ )
  574. {
  575. const IVP_Compact_Edge *pEdge = pTri->get_edge( 0 );
  576. const IVP_U_Float_Point *p0 = IVP_Compact_Ledge_Solver::give_object_coords(pEdge, pLedge);
  577. const IVP_U_Float_Point *p2 = IVP_Compact_Ledge_Solver::give_object_coords(pEdge->get_next(), pLedge);
  578. const IVP_U_Float_Point *p1 = IVP_Compact_Ledge_Solver::give_object_coords(pEdge->get_prev(), pLedge);
  579. plane.calc_hesse(p0, p2, p1);
  580. float testLen = plane.real_length();
  581. // if the triangle is less than 1mm on each side then skip it
  582. if ( testLen > 1e-6f )
  583. {
  584. plane.normize();
  585. halfspaces.add_halfspace( &plane );
  586. }
  587. pTri = pTri->get_next_tri();
  588. }
  589. IVP_Compact_Ledge *pLedgeOut = IVP_SurfaceBuilder_Halfspacesoup::convert_halfspacesoup_to_compact_ledge( &halfspaces, mergeTolerance );
  590. return reinterpret_cast<CPhysConvex *>( pLedgeOut );
  591. }
  592. CPhysConvex *CPhysicsCollision::ConvexFromVerts( Vector **pVerts, int vertCount )
  593. {
  594. CPhysConvex *pConvex = ConvexFromVertsFast( pVerts, vertCount );
  595. CPhysConvex *pReturn = RebuildConvexFromPlanes( pConvex, 0.01f ); // remove interior coplanar verts!
  596. if ( pReturn )
  597. {
  598. ConvexFree( pConvex );
  599. return pReturn;
  600. }
  601. return pConvex;
  602. }
  603. // produce a convex element from planes (csg of planes)
  604. CPhysConvex *CPhysicsCollision::ConvexFromPlanes( float *pPlanes, int planeCount, float mergeDistance )
  605. {
  606. // NOTE: We're passing in planes with outward-facing normals
  607. // Ipion expects inward facing ones; we'll need to reverse plane directon
  608. struct listplane_t
  609. {
  610. float normal[3];
  611. float dist;
  612. };
  613. listplane_t *pList = (listplane_t *)pPlanes;
  614. IVP_U_Hesse plane;
  615. IVP_Halfspacesoup halfspaces;
  616. mergeDistance = ConvertDistanceToIVP( mergeDistance );
  617. for ( int i = 0; i < planeCount; i++ )
  618. {
  619. Vector tmp( -pList[i].normal[0], -pList[i].normal[1], -pList[i].normal[2] );
  620. ConvertPlaneToIVP( tmp, -pList[i].dist, plane );
  621. halfspaces.add_halfspace( &plane );
  622. }
  623. IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Halfspacesoup::convert_halfspacesoup_to_compact_ledge( &halfspaces, mergeDistance );
  624. return reinterpret_cast<CPhysConvex *>( pLedge );
  625. }
  626. CPhysConvex *CPhysicsCollision::ConvexFromConvexPolyhedron( const CPolyhedron &ConvexPolyhedron )
  627. {
  628. IVP_Template_Polygon polyTemplate(ConvexPolyhedron.iVertexCount, ConvexPolyhedron.iLineCount, ConvexPolyhedron.iPolygonCount );
  629. //convert/copy coordinates
  630. for( int i = 0; i != ConvexPolyhedron.iVertexCount; ++i )
  631. ConvertPositionToIVP( ConvexPolyhedron.pVertices[i], polyTemplate.points[i] );
  632. //copy lines
  633. for( int i = 0; i != ConvexPolyhedron.iLineCount; ++i )
  634. polyTemplate.lines[i].set( ConvexPolyhedron.pLines[i].iPointIndices[0], ConvexPolyhedron.pLines[i].iPointIndices[1] );
  635. //copy polygons
  636. for( int i = 0; i != ConvexPolyhedron.iPolygonCount; ++i )
  637. {
  638. polyTemplate.surfaces[i].init_surface( ConvexPolyhedron.pPolygons[i].iIndexCount ); //num vertices in a convex polygon == num lines
  639. polyTemplate.surfaces[i].templ_poly = &polyTemplate;
  640. ConvertPositionToIVP( ConvexPolyhedron.pPolygons[i].polyNormal, polyTemplate.surfaces[i].normal );
  641. Polyhedron_IndexedLineReference_t *pLineReferences = &ConvexPolyhedron.pIndices[ConvexPolyhedron.pPolygons[i].iFirstIndex];
  642. for( int j = 0; j != ConvexPolyhedron.pPolygons[i].iIndexCount; ++j )
  643. {
  644. polyTemplate.surfaces[i].lines[j] = pLineReferences[j].iLineIndex;
  645. polyTemplate.surfaces[i].revert_line[j] = pLineReferences[j].iEndPointIndex;
  646. }
  647. }
  648. //final conversion
  649. IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Polygon_Convex::convert_template_to_ledge(&polyTemplate);
  650. //cleanup
  651. for( int i = 0; i != ConvexPolyhedron.iPolygonCount; ++i )
  652. polyTemplate.surfaces[i].close_surface();
  653. return reinterpret_cast<CPhysConvex *>(pLedge);
  654. }
  655. struct PolyhedronMesh_Triangle
  656. {
  657. struct
  658. {
  659. int iPointIndices[2];
  660. } Edges[3];
  661. };
  662. //TODO: Optimize the returned polyhedron to get away from the triangulated mesh
  663. CPolyhedron *CPhysicsCollision::PolyhedronFromConvex( CPhysConvex * const pConvex, bool bUseTempPolyhedron )
  664. {
  665. IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex;
  666. int iTriangles = pLedge->get_n_triangles();
  667. PolyhedronMesh_Triangle *pTriangles = (PolyhedronMesh_Triangle *)stackalloc( iTriangles * sizeof( PolyhedronMesh_Triangle ) );
  668. int iHighestPointIndex = 0;
  669. const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  670. for( int i = 0; i != iTriangles; ++i )
  671. {
  672. //reverse point ordering while creating edges
  673. pTriangles[i].Edges[2].iPointIndices[1] = pTriangles[i].Edges[0].iPointIndices[0] = pTri->get_edge( 2 )->get_start_point_index();
  674. pTriangles[i].Edges[0].iPointIndices[1] = pTriangles[i].Edges[1].iPointIndices[0] = pTri->get_edge( 1 )->get_start_point_index();
  675. pTriangles[i].Edges[1].iPointIndices[1] = pTriangles[i].Edges[2].iPointIndices[0] = pTri->get_edge( 0 )->get_start_point_index();
  676. for( int j = 0; j != 3; ++j )
  677. {
  678. //get_n_points() has a whole bunch of ifdefs that apparently disable it in this case, detect number of points
  679. if( pTriangles[i].Edges[j].iPointIndices[0] > iHighestPointIndex )
  680. iHighestPointIndex = pTriangles[i].Edges[j].iPointIndices[0];
  681. }
  682. pTri = pTri->get_next_tri();
  683. }
  684. ++iHighestPointIndex;
  685. //apparently points might be shared between ledges and not all points will be used. So now we get to compress them into a smaller set
  686. int *pPointRemapping = (int *)stackalloc( iHighestPointIndex * sizeof( int ) );
  687. memset( pPointRemapping, 0, iHighestPointIndex * sizeof( int ) );
  688. for( int i = 0; i != iTriangles; ++i )
  689. {
  690. for( int j = 0; j != 3; ++j )
  691. ++(pPointRemapping[pTriangles[i].Edges[j].iPointIndices[0]]);
  692. }
  693. int iInsertIndex = 0;
  694. for( int i = 0; i != iHighestPointIndex; ++i )
  695. {
  696. if( pPointRemapping[i] )
  697. {
  698. pPointRemapping[i] = iInsertIndex;
  699. ++iInsertIndex;
  700. }
  701. else
  702. {
  703. pPointRemapping[i] = -1;
  704. }
  705. }
  706. const int iNumPoints = iInsertIndex;
  707. for( int i = 0; i != iTriangles; ++i )
  708. {
  709. for( int j = 0; j != 3; ++j )
  710. {
  711. for( int k = 0; k != 2; ++k )
  712. pTriangles[i].Edges[j].iPointIndices[k] = pPointRemapping[pTriangles[i].Edges[j].iPointIndices[k]];
  713. }
  714. }
  715. bool *bLinks = (bool *)stackalloc( iNumPoints * iNumPoints * sizeof( bool ) );
  716. memset( bLinks, 0, iNumPoints * iNumPoints * sizeof( bool ) );
  717. int iLinkCount = 0;
  718. for( int i = 0; i != iTriangles; ++i )
  719. {
  720. for( int j = 0; j != 3; ++j )
  721. {
  722. const int *pIndices = pTriangles[i].Edges[j].iPointIndices;
  723. int iLow = ((pIndices[0] > pIndices[1])?1:(0));
  724. ++iLinkCount; //this will technically make the link count double the actual number
  725. bLinks[(pIndices[iLow] * iNumPoints) + pIndices[1-iLow]] = true;
  726. }
  727. }
  728. iLinkCount /= 2; //cut the link count in half since we overcounted
  729. CPolyhedron *pReturn;
  730. if( bUseTempPolyhedron )
  731. pReturn = GetTempPolyhedron( iNumPoints, iLinkCount, iLinkCount * 2, iTriangles );
  732. else
  733. pReturn = CPolyhedron_AllocByNew::Allocate( iNumPoints, iLinkCount, iLinkCount * 2, iTriangles );
  734. //copy/convert vertices
  735. const IVP_Compact_Poly_Point *pLedgePoints = pLedge->get_point_array();
  736. Vector *pWriteVertices = pReturn->pVertices;
  737. for( int i = 0; i != iHighestPointIndex; ++i )
  738. {
  739. if( pPointRemapping[i] != -1 )
  740. ConvertPositionToHL( pLedgePoints[i], pWriteVertices[pPointRemapping[i]] );
  741. }
  742. //convert lines
  743. iInsertIndex = 0;
  744. for( int i = 0; i != iNumPoints; ++i )
  745. {
  746. for( int j = i + 1; j != iNumPoints; ++j )
  747. {
  748. if( bLinks[(i * iNumPoints) + j] )
  749. {
  750. pReturn->pLines[iInsertIndex].iPointIndices[0] = i;
  751. pReturn->pLines[iInsertIndex].iPointIndices[1] = j;
  752. ++iInsertIndex;
  753. }
  754. }
  755. }
  756. int *pStartIndices = (int *)stackalloc( iNumPoints * sizeof( int ) ); //for quicker lookup of which edges to use in polygons
  757. pStartIndices[0] = 0; //the lowest index point drives links, so if the first point isn't the first link, then something is extremely messed up
  758. Assert( pReturn->pLines[0].iPointIndices[0] == 0 );
  759. iInsertIndex = 1;
  760. for( int i = 1; i != iNumPoints; ++i )
  761. {
  762. for( int j = iInsertIndex; j != iLinkCount; ++j )
  763. {
  764. if( pReturn->pLines[j].iPointIndices[0] == i )
  765. {
  766. pStartIndices[i] = j;
  767. iInsertIndex = j + 1;
  768. break;
  769. }
  770. }
  771. }
  772. //convert polygons and setup line references as a subtask
  773. iInsertIndex = 0;
  774. for( int i = 0; i != iTriangles; ++i )
  775. {
  776. pReturn->pPolygons[i].iFirstIndex = iInsertIndex;
  777. pReturn->pPolygons[i].iIndexCount = 3;
  778. Vector *p1, *p2, *p3;
  779. p1 = &pReturn->pVertices[pTriangles[i].Edges[0].iPointIndices[0]];
  780. p2 = &pReturn->pVertices[pTriangles[i].Edges[1].iPointIndices[0]];
  781. p3 = &pReturn->pVertices[pTriangles[i].Edges[2].iPointIndices[0]];
  782. Vector v1to2, v1to3;
  783. v1to2 = *p2 - *p1;
  784. v1to3 = *p3 - *p1;
  785. pReturn->pPolygons[i].polyNormal = v1to3.Cross( v1to2 );
  786. pReturn->pPolygons[i].polyNormal.NormalizeInPlace();
  787. for( int j = 0; j != 3; ++j, ++iInsertIndex )
  788. {
  789. const int *pIndices = pTriangles[i].Edges[j].iPointIndices;
  790. int iLow = (pIndices[0] > pIndices[1])?1:0;
  791. int iLineIndex;
  792. for( iLineIndex = pStartIndices[pIndices[iLow]]; iLineIndex != iLinkCount; ++iLineIndex )
  793. {
  794. if( (pReturn->pLines[iLineIndex].iPointIndices[0] == pIndices[iLow]) &&
  795. (pReturn->pLines[iLineIndex].iPointIndices[1] == pIndices[1 - iLow]) )
  796. {
  797. break;
  798. }
  799. }
  800. pReturn->pIndices[iInsertIndex].iLineIndex = iLineIndex;
  801. pReturn->pIndices[iInsertIndex].iEndPointIndex = 1 - iLow;
  802. }
  803. }
  804. return pReturn;
  805. }
  806. int CPhysicsCollision::GetConvexesUsedInCollideable( const CPhysCollide *pCollideable, CPhysConvex **pOutputArray, int iOutputArrayLimit )
  807. {
  808. IVP_U_BigVector<IVP_Compact_Ledge> ledges;
  809. pCollideable->GetAllLedges( ledges );
  810. int iLedgeCount = ledges.len();
  811. if( iLedgeCount > iOutputArrayLimit )
  812. iLedgeCount = iOutputArrayLimit;
  813. for( int i = 0; i != iLedgeCount; ++i )
  814. {
  815. IVP_Compact_Ledge *pLedge = ledges.element_at(i); //doing as a 2 step since a single convert seems more error prone (without compile error) in this case
  816. pOutputArray[i] = (CPhysConvex *)pLedge;
  817. }
  818. return iLedgeCount;
  819. }
  820. void CPhysicsCollision::ConvexesFromConvexPolygon( const Vector &vPolyNormal, const Vector *pPoints, int iPointCount, CPhysConvex **pOutput )
  821. {
  822. IVP_U_Point *pIVP_Points = (IVP_U_Point *)stackalloc( sizeof( IVP_U_Point ) * iPointCount );
  823. IVP_U_Point **pTriangulator = (IVP_U_Point **)stackalloc( sizeof( IVP_U_Point * ) * iPointCount );
  824. IVP_U_Point **pRead = pTriangulator;
  825. IVP_U_Point **pWrite = pTriangulator;
  826. //convert coordinates
  827. {
  828. for( int i = 0; i != iPointCount; ++i )
  829. ConvertPositionToIVP( pPoints[i], pIVP_Points[i] );
  830. }
  831. int iOutputCount = 0;
  832. //chunk this out like a triangle strip
  833. int iForwardCounter = 1;
  834. int iReverseCounter = iPointCount - 1; //guaranteed to be >= 2 to start
  835. *pWrite = &pIVP_Points[0];
  836. ++pWrite;
  837. *pWrite = &pIVP_Points[iReverseCounter];
  838. ++pWrite;
  839. --iReverseCounter;
  840. do
  841. {
  842. //forward
  843. *pWrite = &pIVP_Points[iForwardCounter];
  844. ++iForwardCounter;
  845. pOutput[iOutputCount] = reinterpret_cast<CPhysConvex *>(IVP_SurfaceBuilder_Pointsoup::convert_triangle_to_compace_ledge( pRead[0], pRead[1], pRead[2] ));
  846. Assert( pOutput[iOutputCount] );
  847. ++iOutputCount;
  848. if( iForwardCounter > iReverseCounter )
  849. break;
  850. ++pRead;
  851. ++pWrite;
  852. //backward
  853. *pWrite = &pIVP_Points[iReverseCounter];
  854. --iReverseCounter;
  855. pOutput[iOutputCount] = reinterpret_cast<CPhysConvex *>(IVP_SurfaceBuilder_Pointsoup::convert_triangle_to_compace_ledge( pRead[0], pRead[1], pRead[2] ));
  856. Assert( pOutput[iOutputCount] );
  857. ++iOutputCount;
  858. if( iForwardCounter > iReverseCounter )
  859. break;
  860. ++pRead;
  861. ++pWrite;
  862. } while( true );
  863. }
  864. //-----------------------------------------------------------------------------
  865. // Purpose: copies the first vert int pLedge to out
  866. // Input : *pLedge - compact ledge
  867. // *out - destination float array for the vert
  868. //-----------------------------------------------------------------------------
  869. static void LedgeInsidePoint( IVP_Compact_Ledge *pLedge, Vector& out )
  870. {
  871. IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  872. const IVP_Compact_Edge *pEdge = pTri->get_edge( 0 );
  873. const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge );
  874. ConvertPositionToHL( *pPoint, out );
  875. }
  876. //-----------------------------------------------------------------------------
  877. // Purpose: Calculate the volume of a tetrahedron with these vertices
  878. // Input : p0 - points of tetrahedron
  879. // p1 -
  880. // p2 -
  881. // p3 -
  882. // Output : float (volume in units^3)
  883. //-----------------------------------------------------------------------------
  884. static float TetrahedronVolume( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3 )
  885. {
  886. Vector a, b, c, cross;
  887. float volume = 1.0f / 6.0f;
  888. a = p1 - p0;
  889. b = p2 - p0;
  890. c = p3 - p0;
  891. cross = CrossProduct( b, c );
  892. volume *= DotProduct( a, cross );
  893. if ( volume < 0 )
  894. return -volume;
  895. return volume;
  896. }
  897. static float TriangleArea( const Vector &p0, const Vector &p1, const Vector &p2 )
  898. {
  899. Vector e0 = p1 - p0;
  900. Vector e1 = p2 - p0;
  901. Vector cross;
  902. CrossProduct( e0, e1, cross );
  903. return 0.5 * cross.Length();
  904. }
  905. //-----------------------------------------------------------------------------
  906. // Purpose: Tetrahedronalize this ledge and compute it's volume in BSP space
  907. // Input : convex - the ledge
  908. // Output : float - volume in HL units (in^3)
  909. //-----------------------------------------------------------------------------
  910. float CPhysicsCollision::ConvexVolume( CPhysConvex *pConvex )
  911. {
  912. IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex;
  913. int triangleCount = pLedge->get_n_triangles();
  914. IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  915. Vector vert;
  916. float volume = 0;
  917. // vert is in HL units
  918. LedgeInsidePoint( pLedge, vert );
  919. for ( int j = 0; j < triangleCount; j++ )
  920. {
  921. Vector points[3];
  922. for ( int k = 0; k < 3; k++ )
  923. {
  924. const IVP_Compact_Edge *pEdge = pTri->get_edge( k );
  925. const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge );
  926. ConvertPositionToHL( *pPoint, points[k] );
  927. }
  928. volume += TetrahedronVolume( vert, points[0], points[1], points[2] );
  929. pTri = pTri->get_next_tri();
  930. }
  931. return volume;
  932. }
  933. float CPhysicsCollision::ConvexSurfaceArea( CPhysConvex *pConvex )
  934. {
  935. IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex;
  936. int triangleCount = pLedge->get_n_triangles();
  937. IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  938. float area = 0;
  939. for ( int j = 0; j < triangleCount; j++ )
  940. {
  941. Vector points[3];
  942. for ( int k = 0; k < 3; k++ )
  943. {
  944. const IVP_Compact_Edge *pEdge = pTri->get_edge( k );
  945. const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge );
  946. ConvertPositionToHL( *pPoint, points[k] );
  947. }
  948. area += TriangleArea( points[0], points[1], points[2] );
  949. pTri = pTri->get_next_tri();
  950. }
  951. return area;
  952. }
  953. // Convert an array of convex elements to a compiled collision model (this deletes the convex elements)
  954. CPhysCollide *CPhysicsCollision::ConvertConvexToCollide( CPhysConvex **pConvex, int convexCount )
  955. {
  956. convertconvexparams_t convertParams;
  957. convertParams.Defaults();
  958. return ConvertConvexToCollideParams( pConvex, convexCount, convertParams );
  959. }
  960. CPhysCollide *CPhysicsCollision::ConvertConvexToCollideParams( CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams )
  961. {
  962. if ( !convexCount || !pConvex )
  963. return NULL;
  964. int validConvex = 0;
  965. BEGIN_IVP_ALLOCATION();
  966. IVP_SurfaceBuilder_Ledge_Soup builder;
  967. IVP_Compact_Surface *pSurface = NULL;
  968. for ( int i = 0; i < convexCount; i++ )
  969. {
  970. if ( pConvex[i] )
  971. {
  972. validConvex++;
  973. builder.insert_ledge( (IVP_Compact_Ledge *)pConvex[i] );
  974. }
  975. }
  976. // if the outside code does something stupid, don't crash
  977. if ( validConvex )
  978. {
  979. IVP_Template_Surbuild_LedgeSoup params;
  980. params.force_convex_hull = (IVP_Compact_Ledge *)convertParams.pForcedOuterHull;
  981. params.build_root_convex_hull = convertParams.buildOuterConvexHull ? IVP_TRUE : IVP_FALSE;
  982. // NOTE: THIS FREES THE LEDGES in pConvex!!!
  983. pSurface = builder.compile( &params );
  984. CPhysCollide *pCollide = new CPhysCollideCompactSurface( pSurface );
  985. if ( convertParams.buildDragAxisAreas )
  986. {
  987. pCollide->ComputeOrthographicAreas( convertParams.dragAreaEpsilon );
  988. }
  989. END_IVP_ALLOCATION();
  990. return pCollide;
  991. }
  992. END_IVP_ALLOCATION();
  993. return NULL;
  994. }
  995. static void InitBoxVerts( Vector *boxVerts, Vector **ppVerts, const Vector &mins, const Vector &maxs )
  996. {
  997. for (int i = 0; i < 8; ++i)
  998. {
  999. boxVerts[i][0] = (i & 0x1) ? maxs[0] : mins[0];
  1000. boxVerts[i][1] = (i & 0x2) ? maxs[1] : mins[1];
  1001. boxVerts[i][2] = (i & 0x4) ? maxs[2] : mins[2];
  1002. if ( ppVerts )
  1003. {
  1004. ppVerts[i] = &boxVerts[i];
  1005. }
  1006. }
  1007. }
  1008. #define FAST_BBOX 1
  1009. CPhysCollideCompactSurface *CPhysicsCollision::FastBboxCollide( const CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs )
  1010. {
  1011. Vector boxVerts[8];
  1012. InitBoxVerts( boxVerts, NULL, mins, maxs );
  1013. // copy the compact ledge at bboxCache 0
  1014. // stuff the verts in there
  1015. const IVP_Compact_Surface *pSurface = ConvertPhysCollideToCompactSurface( pCollide );
  1016. Assert( pSurface );
  1017. const IVP_Compact_Ledgetree_Node *node = pSurface->get_compact_ledge_tree_root();
  1018. Assert( node->is_terminal() == IVP_TRUE );
  1019. const IVP_Compact_Ledge *pLedge = node->get_compact_ledge();
  1020. int ledgeSize = pLedge->get_size();
  1021. IVP_Compact_Ledge *pNewLedge = (IVP_Compact_Ledge *)ivp_malloc_aligned( ledgeSize, 16 );
  1022. memcpy( pNewLedge, pLedge, ledgeSize );
  1023. pNewLedge->set_client_data(0);
  1024. IVP_Compact_Poly_Point *pPoints = pNewLedge->get_point_array();
  1025. for ( int i = 0; i < 8; i++ )
  1026. {
  1027. IVP_U_Float_Hesse ivp;
  1028. ConvertPositionToIVP( boxVerts[m_bboxVertMap[i]], ivp );
  1029. ivp.hesse_val = 0;
  1030. pPoints[i].set4(&ivp);
  1031. }
  1032. CPhysConvex *pConvex = (CPhysConvex *)pNewLedge;
  1033. return (CPhysCollideCompactSurface *)ConvertConvexToCollide( &pConvex, 1 );
  1034. }
  1035. void CPhysicsCollision::InitBBoxCache()
  1036. {
  1037. Vector boxVerts[8], *ppVerts[8];
  1038. Vector mins(-16,-16,0), maxs(16,16,72);
  1039. // init with the player box
  1040. InitBoxVerts( boxVerts, ppVerts, mins, maxs );
  1041. // Generate a convex hull from the verts
  1042. CPhysConvex *pConvex = ConvexFromVertsFast( ppVerts, 8 );
  1043. IVP_Compact_Poly_Point *pPoints = reinterpret_cast<IVP_Compact_Ledge *>(pConvex)->get_point_array();
  1044. for ( int i = 0; i < 8; i++ )
  1045. {
  1046. int nearest = -1;
  1047. float minDist = 0.1;
  1048. Vector tmp;
  1049. ConvertPositionToHL( pPoints[i], tmp );
  1050. for ( int j = 0; j < 8; j++ )
  1051. {
  1052. float dist = (boxVerts[j] - tmp).Length();
  1053. if ( dist < minDist )
  1054. {
  1055. minDist = dist;
  1056. nearest = j;
  1057. }
  1058. }
  1059. m_bboxVertMap[i] = nearest;
  1060. #if _DEBUG
  1061. for ( int k = 0; k < i; k++ )
  1062. {
  1063. Assert( m_bboxVertMap[k] != m_bboxVertMap[i] );
  1064. }
  1065. #endif
  1066. // NOTE: If this is wrong, you can disable FAST_BBOX above to fix
  1067. AssertMsg( nearest != -1, "CPhysCollide: Vert map is wrong\n" );
  1068. }
  1069. CPhysCollide *pCollide = ConvertConvexToCollide( &pConvex, 1 );
  1070. AddBBoxCache( (CPhysCollideCompactSurface *)pCollide, mins, maxs );
  1071. }
  1072. CPhysConvex *CPhysicsCollision::BBoxToConvex( const Vector &mins, const Vector &maxs )
  1073. {
  1074. Vector boxVerts[8], *ppVerts[8];
  1075. InitBoxVerts( boxVerts, ppVerts, mins, maxs );
  1076. // Generate a convex hull from the verts
  1077. return ConvexFromVertsFast( ppVerts, 8 );
  1078. }
  1079. CPhysCollide *CPhysicsCollision::BBoxToCollide( const Vector &mins, const Vector &maxs )
  1080. {
  1081. // can't create a collision model for an empty box !
  1082. if ( mins == maxs )
  1083. {
  1084. Assert(0);
  1085. return NULL;
  1086. }
  1087. // find this bbox in the cache
  1088. CPhysCollide *pCollide = GetBBoxCache( mins, maxs );
  1089. if ( pCollide )
  1090. return pCollide;
  1091. // FAST_BBOX: uses an existing compact ledge as a template for fast generation
  1092. // building convex hulls from points is slow
  1093. #if FAST_BBOX
  1094. if ( m_bboxCache.Count() == 0 )
  1095. {
  1096. InitBBoxCache();
  1097. }
  1098. pCollide = FastBboxCollide( m_bboxCache[0].pCollide, mins, maxs );
  1099. #else
  1100. CPhysConvex *pConvex = BBoxToConvex( mins, maxs );
  1101. pCollide = ConvertConvexToCollide( &pConvex, 1 );
  1102. #endif
  1103. AddBBoxCache( (CPhysCollideCompactSurface *)pCollide, mins, maxs );
  1104. return pCollide;
  1105. }
  1106. bool CPhysicsCollision::IsBBoxCache( CPhysCollide *pCollide )
  1107. {
  1108. // UNDONE: Sort the list so it can be searched spatially instead of linearly?
  1109. for ( int i = m_bboxCache.Count()-1; i >= 0; i-- )
  1110. {
  1111. if ( m_bboxCache[i].pCollide == pCollide )
  1112. return true;
  1113. }
  1114. return false;
  1115. }
  1116. void CPhysicsCollision::AddBBoxCache( CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs )
  1117. {
  1118. int index = m_bboxCache.AddToTail();
  1119. bboxcache_t *pCache = &m_bboxCache[index];
  1120. pCache->pCollide = pCollide;
  1121. pCache->mins = mins;
  1122. pCache->maxs = maxs;
  1123. }
  1124. CPhysCollideCompactSurface *CPhysicsCollision::GetBBoxCache( const Vector &mins, const Vector &maxs )
  1125. {
  1126. for ( int i = m_bboxCache.Count()-1; i >= 0; i-- )
  1127. {
  1128. if ( m_bboxCache[i].mins == mins && m_bboxCache[i].maxs == maxs )
  1129. return m_bboxCache[i].pCollide;
  1130. }
  1131. return NULL;
  1132. }
  1133. void CPhysicsCollision::ConvexFree( CPhysConvex *pConvex )
  1134. {
  1135. if ( !pConvex )
  1136. return;
  1137. ivp_free_aligned( pConvex );
  1138. }
  1139. // Get the size of the collision model for serialization
  1140. int CPhysicsCollision::CollideSize( CPhysCollide *pCollide )
  1141. {
  1142. return pCollide->GetSerializationSize();
  1143. }
  1144. int CPhysicsCollision::CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap )
  1145. {
  1146. return pCollide->SerializeToBuffer( pDest, bSwap );
  1147. }
  1148. CPhysCollide *CPhysicsCollision::UnserializeCollide( char *pBuffer, int size, int index )
  1149. {
  1150. return CPhysCollide::UnserializeFromBuffer( pBuffer, size, index );
  1151. }
  1152. class CPhysPolysoup
  1153. {
  1154. public:
  1155. CPhysPolysoup();
  1156. #if ENABLE_IVP_MOPP
  1157. IVP_SurfaceBuilder_Mopp m_builder;
  1158. #endif
  1159. IVP_SurfaceBuilder_Ledge_Soup m_builderSoup;
  1160. IVP_U_Vector<IVP_U_Point> m_points;
  1161. IVP_U_Point m_triangle[3];
  1162. bool m_isValid;
  1163. };
  1164. CPhysPolysoup::CPhysPolysoup()
  1165. {
  1166. m_isValid = false;
  1167. m_points.add( &m_triangle[0] );
  1168. m_points.add( &m_triangle[1] );
  1169. m_points.add( &m_triangle[2] );
  1170. }
  1171. CPhysPolysoup *CPhysicsCollision::PolysoupCreate( void )
  1172. {
  1173. return new CPhysPolysoup;
  1174. }
  1175. void CPhysicsCollision::PolysoupDestroy( CPhysPolysoup *pSoup )
  1176. {
  1177. delete pSoup;
  1178. }
  1179. void CPhysicsCollision::PolysoupAddTriangle( CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits )
  1180. {
  1181. pSoup->m_isValid = true;
  1182. ConvertPositionToIVP( a, pSoup->m_triangle[0] );
  1183. ConvertPositionToIVP( b, pSoup->m_triangle[1] );
  1184. ConvertPositionToIVP( c, pSoup->m_triangle[2] );
  1185. IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Pointsoup::convert_pointsoup_to_compact_ledge(&pSoup->m_points);
  1186. if ( !pLedge )
  1187. {
  1188. Warning("Degenerate Triangle\n");
  1189. Warning("(%.2f, %.2f, %.2f), ", a.x, a.y, a.z );
  1190. Warning("(%.2f, %.2f, %.2f), ", b.x, b.y, b.z );
  1191. Warning("(%.2f, %.2f, %.2f)\n", c.x, c.y, c.z );
  1192. return;
  1193. }
  1194. IVP_Compact_Triangle *pTriangle = pLedge->get_first_triangle();
  1195. pTriangle->set_material_index( materialIndex7bits );
  1196. #if ENABLE_IVP_MOPP
  1197. pSoup->m_builder.insert_ledge(pLedge);
  1198. #endif
  1199. pSoup->m_builderSoup.insert_ledge(pLedge);
  1200. }
  1201. CPhysCollide *CPhysicsCollision::ConvertPolysoupToCollide( CPhysPolysoup *pSoup, bool useMOPP )
  1202. {
  1203. if ( !pSoup->m_isValid )
  1204. return NULL;
  1205. CPhysCollide *pCollide = NULL;
  1206. #if ENABLE_IVP_MOPP
  1207. if ( useMOPP )
  1208. {
  1209. IVP_Compact_Mopp *pSurface = pSoup->m_builder.compile();
  1210. pCollide = new CPhysCollideMopp( pSurface );
  1211. }
  1212. else
  1213. #endif
  1214. {
  1215. IVP_Compact_Surface *pSurface = pSoup->m_builderSoup.compile();
  1216. pCollide = new CPhysCollideCompactSurface( pSurface );
  1217. }
  1218. Assert(pCollide);
  1219. // There's a bug in IVP where the duplicated triangles (for 2D)
  1220. // don't get the materials set properly, so copy them
  1221. IVP_U_BigVector<IVP_Compact_Ledge> ledges;
  1222. pCollide->GetAllLedges( ledges );
  1223. for ( int i = 0; i < ledges.len(); i++ )
  1224. {
  1225. IVP_Compact_Ledge *pLedge = ledges.element_at( i );
  1226. int triangleCount = pLedge->get_n_triangles();
  1227. IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  1228. int materialIndex = pTri->get_material_index();
  1229. if ( !materialIndex )
  1230. {
  1231. for ( int j = 0; j < triangleCount; j++ )
  1232. {
  1233. if ( pTri->get_material_index() != 0 )
  1234. {
  1235. materialIndex = pTri->get_material_index();
  1236. }
  1237. pTri = pTri->get_next_tri();
  1238. }
  1239. }
  1240. for ( int j = 0; j < triangleCount; j++ )
  1241. {
  1242. pTri->set_material_index( materialIndex );
  1243. pTri = pTri->get_next_tri();
  1244. }
  1245. }
  1246. return pCollide;
  1247. }
  1248. int CPhysicsCollision::CreateDebugMesh( const CPhysCollide *pCollisionModel, Vector **outVerts )
  1249. {
  1250. int i;
  1251. IVP_U_BigVector<IVP_Compact_Ledge> ledges;
  1252. pCollisionModel->GetAllLedges( ledges );
  1253. int vertCount = 0;
  1254. for ( i = 0; i < ledges.len(); i++ )
  1255. {
  1256. IVP_Compact_Ledge *pLedge = ledges.element_at( i );
  1257. vertCount += pLedge->get_n_triangles() * 3;
  1258. }
  1259. Vector *verts = new Vector[ vertCount ];
  1260. int vertIndex = 0;
  1261. for ( i = 0; i < ledges.len(); i++ )
  1262. {
  1263. IVP_Compact_Ledge *pLedge = ledges.element_at( i );
  1264. int triangleCount = pLedge->get_n_triangles();
  1265. IVP_Compact_Triangle *pTri = pLedge->get_first_triangle();
  1266. for ( int j = 0; j < triangleCount; j++ )
  1267. {
  1268. for ( int k = 2; k >= 0; k-- )
  1269. {
  1270. const IVP_Compact_Edge *pEdge = pTri->get_edge( k );
  1271. const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge );
  1272. Vector* pVec = verts + vertIndex;
  1273. ConvertPositionToHL( *pPoint, *pVec );
  1274. vertIndex++;
  1275. }
  1276. pTri = pTri->get_next_tri();
  1277. }
  1278. }
  1279. *outVerts = verts;
  1280. return vertCount;
  1281. }
  1282. void CPhysicsCollision::DestroyDebugMesh( int vertCount, Vector *outVerts )
  1283. {
  1284. delete[] outVerts;
  1285. }
  1286. void CPhysicsCollision::SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData )
  1287. {
  1288. IVP_Compact_Ledge *pLedge = reinterpret_cast<IVP_Compact_Ledge *>( pConvex );
  1289. pLedge->set_client_data( gameData );
  1290. }
  1291. void CPhysicsCollision::TraceBox( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr )
  1292. {
  1293. m_traceapi.SweepBoxIVP( start, end, mins, maxs, pCollide, collideOrigin, collideAngles, ptr );
  1294. }
  1295. void CPhysicsCollision::TraceBox( const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr )
  1296. {
  1297. TraceBox( ray, MASK_ALL, NULL, pCollide, collideOrigin, collideAngles, ptr );
  1298. }
  1299. void CPhysicsCollision::TraceBox( const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr )
  1300. {
  1301. m_traceapi.SweepBoxIVP( ray, contentsMask, pConvexInfo, pCollide, collideOrigin, collideAngles, ptr );
  1302. }
  1303. // Trace one collide against another
  1304. void CPhysicsCollision::TraceCollide( const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr )
  1305. {
  1306. m_traceapi.SweepIVP( start, end, pSweepCollide, sweepAngles, pCollide, collideOrigin, collideAngles, ptr );
  1307. }
  1308. void CPhysicsCollision::CollideGetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles )
  1309. {
  1310. m_traceapi.GetAABB( pMins, pMaxs, pCollide, collideOrigin, collideAngles );
  1311. }
  1312. Vector CPhysicsCollision::CollideGetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction )
  1313. {
  1314. if ( !pCollide )
  1315. return collideOrigin;
  1316. return m_traceapi.GetExtent( pCollide, collideOrigin, collideAngles, direction );
  1317. }
  1318. bool CPhysicsCollision::IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone )
  1319. {
  1320. return m_traceapi.IsBoxIntersectingCone( boxAbsMins, boxAbsMaxs, cone );
  1321. }
  1322. // Free a collide that was created with ConvertConvexToCollide()
  1323. void CPhysicsCollision::DestroyCollide( CPhysCollide *pCollide )
  1324. {
  1325. if ( !IsBBoxCache( pCollide ) )
  1326. {
  1327. delete pCollide;
  1328. }
  1329. }
  1330. // calculate the volume of a collide by calling ConvexVolume on its parts
  1331. float CPhysicsCollision::CollideVolume( CPhysCollide *pCollide )
  1332. {
  1333. IVP_U_BigVector<IVP_Compact_Ledge> ledges;
  1334. pCollide->GetAllLedges( ledges );
  1335. float volume = 0;
  1336. for ( int i = 0; i < ledges.len(); i++ )
  1337. {
  1338. volume += ConvexVolume( (CPhysConvex *)ledges.element_at(i) );
  1339. }
  1340. return volume;
  1341. }
  1342. // calculate the volume of a collide by calling ConvexVolume on its parts
  1343. float CPhysicsCollision::CollideSurfaceArea( CPhysCollide *pCollide )
  1344. {
  1345. IVP_U_BigVector<IVP_Compact_Ledge> ledges;
  1346. pCollide->GetAllLedges( ledges );
  1347. float area = 0;
  1348. for ( int i = 0; i < ledges.len(); i++ )
  1349. {
  1350. area += ConvexSurfaceArea( (CPhysConvex *)ledges.element_at(i) );
  1351. }
  1352. return area;
  1353. }
  1354. // loads a set of solids into a vcollide_t
  1355. void CPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int bufferSize, bool swap )
  1356. {
  1357. memset( pOutput, 0, sizeof(*pOutput) );
  1358. int position = 0;
  1359. pOutput->solidCount = solidCount;
  1360. pOutput->solids = new CPhysCollide *[solidCount];
  1361. BEGIN_IVP_ALLOCATION();
  1362. for ( int i = 0; i < solidCount; i++ )
  1363. {
  1364. int size;
  1365. memcpy( &size, pBuffer + position, sizeof(int) );
  1366. position += sizeof(int);
  1367. pOutput->solids[i] = CPhysCollide::UnserializeFromBuffer( pBuffer + position, size, i, swap );
  1368. position += size;
  1369. }
  1370. END_IVP_ALLOCATION();
  1371. pOutput->isPacked = false;
  1372. int keySize = bufferSize - position;
  1373. pOutput->pKeyValues = new char[keySize];
  1374. memcpy( pOutput->pKeyValues, pBuffer + position, keySize );
  1375. pOutput->descSize = 0;
  1376. }
  1377. // destroys the set of solids created by VCollideCreateCPhysCollide
  1378. void CPhysicsCollision::VCollideUnload( vcollide_t *pVCollide )
  1379. {
  1380. for ( int i = 0; i < pVCollide->solidCount; i++ )
  1381. {
  1382. #if _DEBUG
  1383. // HACKHACK: 1024 is just "some big number"
  1384. // GetActiveEnvironmentByIndex() will eventually return NULL when there are no more environments.
  1385. // In HL2 & TF2, there are only 2 environments - so j > 1 is probably an error!
  1386. for ( int j = 0; j < 1024; j++ )
  1387. {
  1388. IPhysicsEnvironment *pEnv = g_PhysicsInternal->GetActiveEnvironmentByIndex( j );
  1389. if ( !pEnv )
  1390. break;
  1391. if ( pEnv->IsCollisionModelUsed( (CPhysCollide *)pVCollide->solids[i] ) )
  1392. {
  1393. AssertMsg(0, "Freed collision model while in use!!!\n");
  1394. return;
  1395. }
  1396. }
  1397. #endif
  1398. delete pVCollide->solids[i];
  1399. }
  1400. delete[] pVCollide->solids;
  1401. delete[] pVCollide->pKeyValues;
  1402. memset( pVCollide, 0, sizeof(*pVCollide) );
  1403. }
  1404. // begins parsing a vcollide. NOTE: This keeps pointers to the vcollide_t
  1405. // If you delete the vcollide_t and call members of IVCollideParse, it will crash
  1406. IVPhysicsKeyParser *CPhysicsCollision::VPhysicsKeyParserCreate( const char *pKeyData )
  1407. {
  1408. return CreateVPhysicsKeyParser( pKeyData );
  1409. }
  1410. // Free the parser created by VPhysicsKeyParserCreate
  1411. void CPhysicsCollision::VPhysicsKeyParserDestroy( IVPhysicsKeyParser *pParser )
  1412. {
  1413. DestroyVPhysicsKeyParser( pParser );
  1414. }
  1415. IPhysicsCollision *CPhysicsCollision::ThreadContextCreate( void )
  1416. {
  1417. return this;
  1418. }
  1419. void CPhysicsCollision::ThreadContextDestroy( IPhysicsCollision *pThreadContext )
  1420. {
  1421. }
  1422. void CPhysicsCollision::CollideGetMassCenter( CPhysCollide *pCollide, Vector *pOutMassCenter )
  1423. {
  1424. *pOutMassCenter = pCollide->GetMassCenter();
  1425. }
  1426. void CPhysicsCollision::CollideSetMassCenter( CPhysCollide *pCollide, const Vector &massCenter )
  1427. {
  1428. pCollide->SetMassCenter( massCenter );
  1429. }
  1430. int CPhysicsCollision::CollideIndex( const CPhysCollide *pCollide )
  1431. {
  1432. if ( !pCollide )
  1433. return 0;
  1434. return pCollide->GetVCollideIndex();
  1435. }
  1436. Vector CPhysicsCollision::CollideGetOrthographicAreas( const CPhysCollide *pCollide )
  1437. {
  1438. if ( !pCollide )
  1439. return vec3_origin;
  1440. return pCollide->GetOrthographicAreas();
  1441. }
  1442. void CPhysicsCollision::CollideSetOrthographicAreas( CPhysCollide *pCollide, const Vector &areas )
  1443. {
  1444. if ( pCollide )
  1445. pCollide->SetOrthographicAreas( areas );
  1446. }
  1447. // returns true if this collide has an outer hull built
  1448. void CPhysicsCollision::OutputDebugInfo( const CPhysCollide *pCollide )
  1449. {
  1450. pCollide->OutputDebugInfo();
  1451. }
  1452. bool CPhysicsCollision::GetBBoxCacheSize( int *pCachedSize, int *pCachedCount )
  1453. {
  1454. *pCachedSize = 0;
  1455. *pCachedCount = m_bboxCache.Count();
  1456. for ( int i = 0; i < *pCachedCount; i++ )
  1457. {
  1458. *pCachedSize += m_bboxCache[i].pCollide->GetSerializationSize();
  1459. }
  1460. return true;
  1461. }
  1462. class CCollisionQuery : public ICollisionQuery
  1463. {
  1464. public:
  1465. CCollisionQuery( CPhysCollide *pCollide );
  1466. ~CCollisionQuery( void ) {}
  1467. // number of convex pieces in the whole solid
  1468. virtual int ConvexCount( void );
  1469. // triangle count for this convex piece
  1470. virtual int TriangleCount( int convexIndex );
  1471. // get the stored game data
  1472. virtual unsigned int GetGameData( int convexIndex );
  1473. // Gets the triangle's verts to an array
  1474. virtual void GetTriangleVerts( int convexIndex, int triangleIndex, Vector *verts );
  1475. // UNDONE: This doesn't work!!!
  1476. virtual void SetTriangleVerts( int convexIndex, int triangleIndex, const Vector *verts );
  1477. // returns the 7-bit material index
  1478. virtual int GetTriangleMaterialIndex( int convexIndex, int triangleIndex );
  1479. // sets a 7-bit material index for this triangle
  1480. virtual void SetTriangleMaterialIndex( int convexIndex, int triangleIndex, int index7bits );
  1481. private:
  1482. IVP_Compact_Triangle *Triangle( IVP_Compact_Ledge *pLedge, int triangleIndex );
  1483. IVP_U_BigVector <IVP_Compact_Ledge> m_ledges;
  1484. };
  1485. // create a queryable version of the collision model
  1486. ICollisionQuery *CPhysicsCollision::CreateQueryModel( CPhysCollide *pCollide )
  1487. {
  1488. return new CCollisionQuery( pCollide );
  1489. }
  1490. // destroy the queryable version
  1491. void CPhysicsCollision::DestroyQueryModel( ICollisionQuery *pQuery )
  1492. {
  1493. delete pQuery;
  1494. }
  1495. CCollisionQuery::CCollisionQuery( CPhysCollide *pCollide )
  1496. {
  1497. pCollide->GetAllLedges( m_ledges );
  1498. }
  1499. // number of convex pieces in the whole solid
  1500. int CCollisionQuery::ConvexCount( void )
  1501. {
  1502. return m_ledges.len();
  1503. }
  1504. // triangle count for this convex piece
  1505. int CCollisionQuery::TriangleCount( int convexIndex )
  1506. {
  1507. IVP_Compact_Ledge *pLedge = m_ledges.element_at(convexIndex);
  1508. if ( pLedge )
  1509. {
  1510. return pLedge->get_n_triangles();
  1511. }
  1512. return 0;
  1513. }
  1514. unsigned int CCollisionQuery::GetGameData( int convexIndex )
  1515. {
  1516. IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex );
  1517. if ( pLedge )
  1518. return pLedge->get_client_data();
  1519. return 0;
  1520. }
  1521. // Gets the triangle's verts to an array
  1522. void CCollisionQuery::GetTriangleVerts( int convexIndex, int triangleIndex, Vector *verts )
  1523. {
  1524. IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex );
  1525. IVP_Compact_Triangle *pTriangle = Triangle( pLedge, triangleIndex );
  1526. int vertIndex = 0;
  1527. for ( int k = 2; k >= 0; k-- )
  1528. {
  1529. const IVP_Compact_Edge *pEdge = pTriangle->get_edge( k );
  1530. const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge );
  1531. Vector* pVec = verts + vertIndex;
  1532. ConvertPositionToHL( *pPoint, *pVec );
  1533. vertIndex++;
  1534. }
  1535. }
  1536. // UNDONE: This doesn't work!!!
  1537. void CCollisionQuery::SetTriangleVerts( int convexIndex, int triangleIndex, const Vector *verts )
  1538. {
  1539. IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex );
  1540. Triangle( pLedge, triangleIndex );
  1541. }
  1542. int CCollisionQuery::GetTriangleMaterialIndex( int convexIndex, int triangleIndex )
  1543. {
  1544. IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex );
  1545. IVP_Compact_Triangle *pTriangle = Triangle( pLedge, triangleIndex );
  1546. return pTriangle->get_material_index();
  1547. }
  1548. void CCollisionQuery::SetTriangleMaterialIndex( int convexIndex, int triangleIndex, int index7bits )
  1549. {
  1550. IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex );
  1551. IVP_Compact_Triangle *pTriangle = Triangle( pLedge, triangleIndex );
  1552. pTriangle->set_material_index( index7bits );
  1553. }
  1554. IVP_Compact_Triangle *CCollisionQuery::Triangle( IVP_Compact_Ledge *pLedge, int triangleIndex )
  1555. {
  1556. if ( !pLedge )
  1557. return NULL;
  1558. return pLedge->get_first_triangle() + triangleIndex;
  1559. }
  1560. #if 0
  1561. void TestCubeVolume( void )
  1562. {
  1563. float volume = 0;
  1564. Vector verts[8];
  1565. typedef struct
  1566. {
  1567. int a, b, c;
  1568. } triangle_t;
  1569. triangle_t triangles[12] =
  1570. {
  1571. {0,1,3}, // front 0123
  1572. {0,3,2},
  1573. {4,5,1}, // top 4501
  1574. {4,1,0},
  1575. {2,3,7}, // bottom 2367
  1576. {2,7,6},
  1577. {1,5,7}, // right 1537
  1578. {1,7,3},
  1579. {4,0,2}, // left 4062
  1580. {4,2,6},
  1581. {5,4,6}, // back 5476
  1582. {5,6,7}
  1583. };
  1584. int i = 0;
  1585. for ( int x = -1; x <= 1; x +=2 )
  1586. for ( int y = -1; y <= 1; y +=2 )
  1587. for ( int z = -1; z <= 1; z +=2 )
  1588. {
  1589. verts[i][0] = x;
  1590. verts[i][1] = y;
  1591. verts[i][2] = z;
  1592. i++;
  1593. }
  1594. for ( i = 0; i < 12; i++ )
  1595. {
  1596. triangle_t *pTri = triangles + i;
  1597. volume += TetrahedronVolume( verts[0], verts[pTri->a], verts[pTri->b], verts[pTri->c] );
  1598. }
  1599. // should report a volume of 8. This is a cube that is 2 on a side
  1600. printf("Test volume %.4f\n", volume );
  1601. }
  1602. #endif