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.

639 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Virtual mesh implementation. Cached terrain collision model
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "convert.h"
  8. #include "ivp_surface_manager.hxx"
  9. #include "ivp_surman_polygon.hxx"
  10. #include "ivp_template_surbuild.hxx"
  11. #include "ivp_compact_surface.hxx"
  12. #include <ivp_compact_ledge.hxx>
  13. #include <ivp_ray_solver.hxx>
  14. #include <ivp_compact_ledge_solver.hxx>
  15. #include "ivp_surbuild_pointsoup.hxx"
  16. #include "ivp_surbuild_ledge_soup.hxx"
  17. #include "physics_trace.h"
  18. #include "collisionutils.h"
  19. #include "datamanager.h"
  20. #include "utlbuffer.h"
  21. #include "ledgewriter.h"
  22. #include "tier1/mempool.h"
  23. #include "tier0/memdbgon.h"
  24. class CPhysCollideVirtualMesh;
  25. CTSPool< CUtlVector<CPhysCollideVirtualMesh *> > g_MeshFrameLocksPool;
  26. CThreadLocalPtr< CUtlVector<CPhysCollideVirtualMesh *> > g_pMeshFrameLocks;
  27. // This is the surfacemanager class for IVP that implements the required functions by layering CPhysCollideVirtualMesh
  28. class IVP_SurfaceManager_VirtualMesh : public IVP_SurfaceManager
  29. {
  30. public:
  31. void add_reference_to_ledge(const IVP_Compact_Ledge *ledge);
  32. void remove_reference_to_ledge(const IVP_Compact_Ledge *ledge);
  33. void insert_all_ledges_hitting_ray(IVP_Ray_Solver *ray_solver, IVP_Real_Object *object);
  34. void get_radius_and_radius_dev_to_given_center(const IVP_U_Float_Point *center, IVP_FLOAT *radius, IVP_FLOAT *radius_deviation) const;
  35. virtual IVP_SURMAN_TYPE get_type() { return IVP_SURMAN_POLYGON; }
  36. // assume mesh is never a single triangle
  37. virtual const IVP_Compact_Ledge *get_single_convex() const;
  38. void get_mass_center(IVP_U_Float_Point *mass_center_out) const;
  39. void get_rotation_inertia( IVP_U_Float_Point *rotation_inertia_out ) const;
  40. void get_all_ledges_within_radius(const IVP_U_Point *observer_os, IVP_DOUBLE radius,
  41. const IVP_Compact_Ledge *root_ledge, IVP_Real_Object *other_object, const IVP_Compact_Ledge *other_reference_ledge,
  42. IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges);
  43. void get_all_terminal_ledges(IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges);
  44. IVP_SurfaceManager_VirtualMesh( CPhysCollideVirtualMesh *pMesh );
  45. virtual ~IVP_SurfaceManager_VirtualMesh();
  46. private:
  47. CPhysCollideVirtualMesh *m_pMesh;
  48. };
  49. // These are the managed objects for the LRU of terrain collisions
  50. // These get created/destroyed dynamically by a resourcemanager
  51. // These contain the uncompressed collision models for each displacement patch
  52. // The idea is to have only the necessary instances of these in memory at any given time - never all of them
  53. class CMeshInstance
  54. {
  55. public:
  56. // resourcemanager
  57. static unsigned int EstimatedSize( const virtualmeshlist_t &list );
  58. static CMeshInstance *CreateResource( const virtualmeshlist_t &list );
  59. static unsigned int ComputeRootLedgeSize( const byte *pHull );
  60. void DestroyResource() { delete this; }
  61. unsigned int Size() { return m_memSize; }
  62. CMeshInstance *GetData() { return this; }
  63. const triangleledge_t *GetLedges() { return (triangleledge_t *)m_pMemory; }
  64. inline int HullCount() { return m_hullCount; }
  65. const IVP_Compact_Ledge *GetOuterHull() { return (m_hullCount==1) ? (const IVP_Compact_Ledge *)(m_pMemory + m_hullOffset) : NULL; }
  66. int GetRootLedges( IVP_Compact_Ledge **pLedges, int outCount )
  67. {
  68. int hullOffset = m_hullOffset;
  69. int count = min(outCount, (int)m_hullCount);
  70. for ( int i = 0; i < count; i++ )
  71. {
  72. pLedges[i] = (IVP_Compact_Ledge *)(m_pMemory + hullOffset);
  73. hullOffset += sizeof(IVP_Compact_Ledge) + (sizeof(IVP_Compact_Triangle) * pLedges[i]->get_n_triangles());
  74. }
  75. return count;
  76. }
  77. // locals
  78. CMeshInstance() { m_pMemory = 0; }
  79. ~CMeshInstance();
  80. private:
  81. void Init( const virtualmeshlist_t &list );
  82. int m_memSize;
  83. char *m_pMemory;
  84. unsigned short m_hullOffset;
  85. byte m_hullCount;
  86. byte m_pad;
  87. };
  88. CMeshInstance::~CMeshInstance()
  89. {
  90. if ( m_pMemory )
  91. {
  92. ivp_free_aligned( m_pMemory );
  93. m_pMemory = NULL;
  94. }
  95. }
  96. unsigned int CMeshInstance::EstimatedSize( const virtualmeshlist_t &list )
  97. {
  98. int ledgeSize = sizeof(triangleledge_t) * list.triangleCount;
  99. int pointSize = sizeof(IVP_Compact_Poly_Point) * list.vertexCount;
  100. int hullSize = ComputeRootLedgeSize(list.pHull);
  101. return ledgeSize + pointSize + hullSize;
  102. }
  103. // computes the unpacked size of the array of root ledges
  104. unsigned int CMeshInstance::ComputeRootLedgeSize( const byte *pData )
  105. {
  106. if ( !pData )
  107. return 0;
  108. virtualmeshhull_t *pHeader = (virtualmeshhull_t *)pData;
  109. packedhull_t *pHull = (packedhull_t *)(pHeader+1);
  110. unsigned int size = pHeader->hullCount * sizeof(IVP_Compact_Ledge);
  111. for ( int i = 0; i < pHeader->hullCount; i++ )
  112. {
  113. size += sizeof(IVP_Compact_Triangle) * pHull[i].triangleCount;
  114. }
  115. return size;
  116. }
  117. CMeshInstance *CMeshInstance::CreateResource( const virtualmeshlist_t &list )
  118. {
  119. CMeshInstance *pMesh = new CMeshInstance;
  120. pMesh->Init( list );
  121. return pMesh;
  122. }
  123. // flat memory footprint has triangleledges (ledge + 2 triangles for terrain), then has verts, then optional convex hull
  124. void CMeshInstance::Init( const virtualmeshlist_t &list )
  125. {
  126. int ledgeSize = sizeof(triangleledge_t) * list.triangleCount;
  127. int pointSize = sizeof(IVP_Compact_Poly_Point) * list.vertexCount;
  128. int memSize = ledgeSize + pointSize + ComputeRootLedgeSize(list.pHull);
  129. m_memSize = memSize;
  130. m_hullCount = 0;
  131. m_pMemory = (char *)ivp_malloc_aligned( memSize, 16 );
  132. Assert( (int(m_pMemory) & 15) == 0 ); // make sure it is aligned
  133. IVP_Compact_Poly_Point *pPoints = (IVP_Compact_Poly_Point *)&m_pMemory[ledgeSize];
  134. triangleledge_t *pLedges = (triangleledge_t *) m_pMemory;
  135. memset( m_pMemory, 0, memSize );
  136. int i;
  137. for ( i = 0; i < list.vertexCount; i++ )
  138. {
  139. ConvertPositionToIVP( list.pVerts[i], pPoints[i] );
  140. }
  141. for ( i = 0; i < list.triangleCount; i++ )
  142. {
  143. Vector v0 = list.pVerts[list.indices[i*3+0]];
  144. Vector v1 = list.pVerts[list.indices[i*3+1]];
  145. Vector v2 = list.pVerts[list.indices[i*3+2]];
  146. Assert( v0 != v1 && v1 != v2 && v0 != v2 );
  147. CVPhysicsVirtualMeshWriter::InitTwoSidedTriangleLege( &pLedges[i], pPoints, list.indices[i*3+0], list.indices[i*3+1], list.indices[i*3+2], 0 );
  148. }
  149. Assert( list.triangleCount > 0 && list.triangleCount <= MAX_VIRTUAL_TRIANGLES );
  150. // if there's a hull, build it out too
  151. if ( list.pHull )
  152. {
  153. virtualmeshhull_t *pHeader = (virtualmeshhull_t *)list.pHull;
  154. m_hullCount = pHeader->hullCount;
  155. Assert( (ledgeSize + pointSize) < 65536 );
  156. m_hullOffset = ledgeSize + pointSize;
  157. byte *pMem = (byte *)m_pMemory + m_hullOffset;
  158. #if _DEBUG
  159. int hullSize = CVPhysicsVirtualMeshWriter::UnpackLedgeListFromHull( pMem, pHeader, pPoints );
  160. Assert((m_hullOffset+hullSize)==memSize);
  161. #else
  162. CVPhysicsVirtualMeshWriter::UnpackLedgeListFromHull( pMem, pHeader, pPoints );
  163. #endif
  164. }
  165. }
  166. // UNDONE: Tune / expose this constant 512K budget for terrain collision
  167. const int g_MeshSize = (2048 * 1024);
  168. static CDataManager<CMeshInstance, virtualmeshlist_t, CMeshInstance *, CThreadFastMutex> g_MeshManager( g_MeshSize );
  169. static int numIndices = 0, numTriangles = 0, numBaseTriangles = 0, numSplits = 0;
  170. //-----------------------------------------------------------------------------
  171. // Purpose: This allows for just-in-time procedural triangle soup data to be
  172. // instanced & cached as IVP collision data (compact ledges)
  173. //-----------------------------------------------------------------------------
  174. // NOTE: This is the permanent in-memory representation. It holds the compressed data
  175. // and the parameters necessary to request the proxy geometry as needed
  176. class CPhysCollideVirtualMesh : public CPhysCollide
  177. {
  178. public:
  179. // UNDONE: Unlike other CPhysCollide objects, operations the virtual mesh are
  180. // non-const because they may instantiate the cache. This causes problems with the interface.
  181. // Maybe the cache stuff should be mutable, but it amounts to the same kind of
  182. // hackery to cast away const.
  183. // get a surface manager
  184. virtual IVP_SurfaceManager *CreateSurfaceManager( short &collideType ) const
  185. {
  186. collideType = COLLIDE_VIRTUAL;
  187. // UNDONE: Figure out how to avoid this const_cast
  188. return new IVP_SurfaceManager_VirtualMesh(const_cast<CPhysCollideVirtualMesh *>(this));
  189. }
  190. virtual void GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const
  191. {
  192. const triangleledge_t *pLedges = const_cast<CPhysCollideVirtualMesh *>(this)->AddRef()->GetLedges();
  193. for ( int i = 0; i < m_ledgeCount; i++ )
  194. {
  195. ledges.add( const_cast<IVP_Compact_Ledge *>(&pLedges[i].ledge) );
  196. }
  197. const_cast<CPhysCollideVirtualMesh *>(this)->Release();
  198. }
  199. virtual unsigned int GetSerializationSize() const
  200. {
  201. if ( !m_pHull )
  202. return 0;
  203. return m_pHull->TotalSize();
  204. }
  205. virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const
  206. {
  207. unsigned int size = GetSerializationSize();
  208. if ( size )
  209. {
  210. memcpy( pDest, m_pHull, size );
  211. }
  212. return size;
  213. }
  214. virtual int GetVCollideIndex() const { return 0; }
  215. virtual void SetMassCenter( const Vector &massCenter ) {Assert(0); }
  216. virtual Vector GetOrthographicAreas() const { return Vector(1,1,1);}
  217. Vector GetMassCenter() const;
  218. virtual float GetSphereRadius() const;
  219. float GetSphereRadiusIVP() const;
  220. void Init( const char *pBuffer, unsigned int size )
  221. {
  222. }
  223. void GetAllLedgesWithinRadius( const IVP_U_Point *observer_os, IVP_DOUBLE radius, IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges, const IVP_Compact_Ledge *pRootLedge = NULL )
  224. {
  225. virtualmeshtrianglelist_t list;
  226. list.triangleCount = 0;
  227. Vector centerHL;
  228. ConvertPositionToHL( *observer_os, centerHL );
  229. float radiusHL = ConvertDistanceToHL(radius);
  230. m_params.pMeshEventHandler->GetTrianglesInSphere( m_params.userData, centerHL, radiusHL, &list );
  231. if ( list.triangleCount )
  232. {
  233. CMeshInstance *pMesh = AddRef();
  234. const triangleledge_t *pLedges = pMesh->GetLedges();
  235. FrameRelease();
  236. // If we have two root ledges, then each one contains half the triangles
  237. // only return triangles indexed under the root ledge being queried
  238. int minTriangle = 0;
  239. int maxTriangle = m_ledgeCount;
  240. if ( pMesh->HullCount() > 1 )
  241. {
  242. Assert(pMesh->HullCount()==2);
  243. IVP_Compact_Ledge *pRootNodes[2];
  244. pMesh->GetRootLedges( pRootNodes, 2 );
  245. int midTriangle = m_ledgeCount/2;
  246. if ( pRootLedge == pRootNodes[0] )
  247. {
  248. maxTriangle = midTriangle;
  249. }
  250. else
  251. {
  252. minTriangle = midTriangle;
  253. }
  254. }
  255. IVP_DOUBLE radiusSq = radius * radius;
  256. for ( int i = 0; i < list.triangleCount; i++ )
  257. {
  258. Assert( list.triangleIndices[i] < m_ledgeCount );
  259. if ( list.triangleIndices[i] < minTriangle || list.triangleIndices[i] >= maxTriangle )
  260. continue;
  261. const IVP_Compact_Ledge *ledge = &pLedges[list.triangleIndices[i]].ledge;
  262. Assert(ledge->get_n_triangles() == 2);
  263. const IVP_Compact_Triangle *triangle = ledge->get_first_triangle();
  264. IVP_DOUBLE qdist = IVP_CLS.calc_qlen_PF_F_space(ledge, triangle, observer_os);
  265. if ( qdist > radiusSq )
  266. {
  267. continue;
  268. }
  269. resulting_ledges->add( const_cast<IVP_Compact_Ledge *>(ledge) );
  270. }
  271. }
  272. }
  273. virtual void OutputDebugInfo() const
  274. {
  275. Msg("Virtual mesh!\n");
  276. }
  277. CPhysCollideVirtualMesh(const virtualmeshparams_t &params) : m_params(params), m_hMemory( INVALID_MEMHANDLE ), m_ledgeCount( 0 )
  278. {
  279. m_pHull = NULL;
  280. if ( params.buildOuterHull )
  281. {
  282. BuildBoundingLedge();
  283. }
  284. }
  285. virtual ~CPhysCollideVirtualMesh();
  286. // adds a lock on the collsion memory :: MUST CALL Release() or FrameRelease corresponding to this call!!!
  287. CMeshInstance *AddRef();
  288. void BuildBoundingLedge();
  289. static virtualmeshhull_t *CreateMeshBoundingHull( const virtualmeshlist_t &list );
  290. static void DestroyMeshBoundingHull(virtualmeshhull_t *pHull) { CVPhysicsVirtualMeshWriter::DestroyPackedHull(pHull); }
  291. static IVP_Compact_Surface *CreateBoundingSurfaceFromRange( const virtualmeshlist_t &list, int firstIndex, int indexCount );
  292. int GetRootLedges( IVP_Compact_Ledge **pLedges, int outCount )
  293. {
  294. int count = AddRef()->GetRootLedges(pLedges, outCount);
  295. FrameRelease();
  296. return count;
  297. }
  298. IVP_Compact_Ledge *GetBoundingLedge()
  299. {
  300. IVP_Compact_Ledge *pLedge = const_cast<IVP_Compact_Ledge *>(AddRef()->GetOuterHull());
  301. FrameRelease();
  302. return pLedge;
  303. }
  304. // releases a lock on the collision memory
  305. void Release();
  306. // Analagous to Release, but happens at the end of the frame
  307. void FrameRelease()
  308. {
  309. CUtlVector<CPhysCollideVirtualMesh *> *pLocks = g_pMeshFrameLocks;
  310. if ( !pLocks )
  311. {
  312. g_pMeshFrameLocks = pLocks = g_MeshFrameLocksPool.GetObject();
  313. Assert( pLocks );
  314. }
  315. pLocks->AddToTail(this);
  316. }
  317. inline void GetBounds( Vector &mins, Vector &maxs ) const
  318. {
  319. m_params.pMeshEventHandler->GetWorldspaceBounds( m_params.userData, &mins, &maxs );
  320. }
  321. private:
  322. CMeshInstance *BuildLedges();
  323. virtualmeshparams_t m_params;
  324. virtualmeshhull_t *m_pHull;
  325. memhandle_t m_hMemory;
  326. short m_ledgeCount;
  327. };
  328. static void FlushFrameLocks()
  329. {
  330. CUtlVector<CPhysCollideVirtualMesh *> *pLocks = g_pMeshFrameLocks;
  331. if ( pLocks )
  332. {
  333. for ( int i = 0; i < pLocks->Count(); i++ )
  334. {
  335. Assert( (*pLocks)[i] );
  336. (*pLocks)[i]->Release();
  337. }
  338. pLocks->RemoveAll();
  339. g_MeshFrameLocksPool.PutObject( g_pMeshFrameLocks );
  340. g_pMeshFrameLocks = NULL;
  341. }
  342. }
  343. void VirtualMeshPSI()
  344. {
  345. FlushFrameLocks();
  346. }
  347. Vector CPhysCollideVirtualMesh::GetMassCenter() const
  348. {
  349. Vector mins, maxs;
  350. GetBounds( mins, maxs );
  351. return 0.5 * (mins + maxs);
  352. }
  353. float CPhysCollideVirtualMesh::GetSphereRadius() const
  354. {
  355. Vector mins, maxs;
  356. GetBounds( mins, maxs );
  357. Vector point = 0.5 * (mins+maxs);
  358. return (maxs - point).Length();
  359. }
  360. float CPhysCollideVirtualMesh::GetSphereRadiusIVP() const
  361. {
  362. return ConvertDistanceToIVP( GetSphereRadius() );
  363. }
  364. static CThreadFastMutex s_BuildVirtualMeshMutex;
  365. CMeshInstance *CPhysCollideVirtualMesh::AddRef()
  366. {
  367. CMeshInstance *pMesh = g_MeshManager.LockResource( m_hMemory );
  368. if ( !pMesh )
  369. {
  370. s_BuildVirtualMeshMutex.Lock();
  371. pMesh = g_MeshManager.LockResource( m_hMemory );
  372. if ( !pMesh )
  373. {
  374. pMesh = BuildLedges();
  375. }
  376. s_BuildVirtualMeshMutex.Unlock();
  377. }
  378. Assert( pMesh );
  379. return pMesh;
  380. }
  381. void CPhysCollideVirtualMesh::Release()
  382. {
  383. g_MeshManager.UnlockResource( m_hMemory );
  384. }
  385. CPhysCollideVirtualMesh::~CPhysCollideVirtualMesh()
  386. {
  387. CVPhysicsVirtualMeshWriter::DestroyPackedHull(m_pHull);
  388. g_MeshManager.DestroyResource( m_hMemory );
  389. }
  390. CMeshInstance *CPhysCollideVirtualMesh::BuildLedges()
  391. {
  392. virtualmeshlist_t list;
  393. m_params.pMeshEventHandler->GetVirtualMesh( m_params.userData, &list );
  394. if ( !list.pHull )
  395. {
  396. list.pHull = (byte *)m_pHull;
  397. }
  398. if ( list.triangleCount )
  399. {
  400. m_hMemory = g_MeshManager.CreateResource( list );
  401. m_ledgeCount = list.triangleCount;
  402. CMeshInstance *pMesh = g_MeshManager.LockResource( m_hMemory );
  403. return pMesh;
  404. }
  405. return NULL;
  406. }
  407. // build the outer ledge, split into two if necessary
  408. void CPhysCollideVirtualMesh::BuildBoundingLedge()
  409. {
  410. virtualmeshlist_t list;
  411. m_params.pMeshEventHandler->GetVirtualMesh( m_params.userData, &list );
  412. m_pHull = CreateMeshBoundingHull(list);
  413. }
  414. virtualmeshhull_t *CPhysCollideVirtualMesh::CreateMeshBoundingHull( const virtualmeshlist_t &list )
  415. {
  416. virtualmeshhull_t *pHull = NULL;
  417. if ( list.triangleCount )
  418. {
  419. IVP_Compact_Surface *pSurface = CreateBoundingSurfaceFromRange( list, 0, list.indexCount );
  420. if ( pSurface )
  421. {
  422. const IVP_Compact_Ledge *pLedge = pSurface->get_compact_ledge_tree_root()->get_compact_hull();
  423. if ( CVPhysicsVirtualMeshWriter::LedgeCanBePacked(pLedge, list) )
  424. {
  425. pHull = CVPhysicsVirtualMeshWriter::CreatePackedHullFromLedges( list, &pLedge, 1 );
  426. }
  427. else
  428. {
  429. // too big to pack to 8-bits, split in two
  430. IVP_Compact_Surface *pSurface0 = CreateBoundingSurfaceFromRange( list, 0, list.indexCount/2 );
  431. IVP_Compact_Surface *pSurface1 = CreateBoundingSurfaceFromRange( list, list.indexCount/2, list.indexCount/2 );
  432. const IVP_Compact_Ledge *pLedges[2] = {pSurface0->get_compact_ledge_tree_root()->get_compact_hull(), pSurface1->get_compact_ledge_tree_root()->get_compact_hull()};
  433. pHull = CVPhysicsVirtualMeshWriter::CreatePackedHullFromLedges( list, pLedges, 2 );
  434. ivp_free_aligned(pSurface0);
  435. ivp_free_aligned(pSurface1);
  436. }
  437. ivp_free_aligned(pSurface);
  438. }
  439. }
  440. return pHull;
  441. }
  442. IVP_Compact_Surface *CPhysCollideVirtualMesh::CreateBoundingSurfaceFromRange( const virtualmeshlist_t &list, int firstIndex, int indexCount )
  443. {
  444. Assert( list.triangleCount );
  445. IVP_U_Point triVerts[3];
  446. IVP_U_Vector<IVP_U_Point> triList;
  447. IVP_SurfaceBuilder_Ledge_Soup builder;
  448. triList.add( &triVerts[0] );
  449. triList.add( &triVerts[1] );
  450. triList.add( &triVerts[2] );
  451. int lastIndex = firstIndex + indexCount;
  452. int firstTriangle = firstIndex/3;
  453. int lastTriangle = lastIndex/3;
  454. for ( int i = firstTriangle; i < lastTriangle; i++ )
  455. {
  456. ConvertPositionToIVP( list.pVerts[list.indices[i*3+0]], triVerts[0] );
  457. ConvertPositionToIVP( list.pVerts[list.indices[i*3+1]], triVerts[1] );
  458. ConvertPositionToIVP( list.pVerts[list.indices[i*3+2]], triVerts[2] );
  459. IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Pointsoup::convert_pointsoup_to_compact_ledge( &triList );
  460. builder.insert_ledge( pLedge );
  461. }
  462. // build a convex hull of those verts
  463. IVP_Template_Surbuild_LedgeSoup params;
  464. params.build_root_convex_hull = IVP_TRUE;
  465. IVP_Compact_Surface *pSurface = builder.compile( &params );
  466. #if _DEBUG
  467. const IVP_Compact_Ledgetree_Node *node = pSurface->get_compact_ledge_tree_root();
  468. IVP_Compact_Ledge *pLedge = const_cast<IVP_Compact_Ledge *>(node->get_compact_hull()); // we're going to write into client data on each vert before we throw this away
  469. Assert(pLedge && !pLedge->is_terminal());
  470. #endif
  471. return pSurface;
  472. }
  473. CPhysCollide *CreateVirtualMesh( const virtualmeshparams_t &params )
  474. {
  475. return new CPhysCollideVirtualMesh(params);
  476. }
  477. void DestroyVirtualMesh( CPhysCollide *pMesh )
  478. {
  479. FlushFrameLocks();
  480. delete pMesh;
  481. }
  482. //-----------------------------------------------------------------------------
  483. // IVP_SurfaceManager_VirtualMesh
  484. // This hooks the underlying collision model to IVP's surfacemanager interface
  485. //-----------------------------------------------------------------------------
  486. IVP_SurfaceManager_VirtualMesh::IVP_SurfaceManager_VirtualMesh( CPhysCollideVirtualMesh *pMesh ) : m_pMesh(pMesh)
  487. {
  488. }
  489. IVP_SurfaceManager_VirtualMesh::~IVP_SurfaceManager_VirtualMesh()
  490. {
  491. }
  492. void IVP_SurfaceManager_VirtualMesh::add_reference_to_ledge(const IVP_Compact_Ledge *ledge)
  493. {
  494. m_pMesh->AddRef();
  495. }
  496. void IVP_SurfaceManager_VirtualMesh::remove_reference_to_ledge(const IVP_Compact_Ledge *ledge)
  497. {
  498. m_pMesh->Release();
  499. }
  500. // Implement the IVP raycast. This is done by testing each triangle (front & back) - so it's slow
  501. void IVP_SurfaceManager_VirtualMesh::insert_all_ledges_hitting_ray(IVP_Ray_Solver *ray_solver, IVP_Real_Object *object)
  502. {
  503. IVP_Vector_of_Ledges_256 ledges;
  504. IVP_Ray_Solver_Os ray_solver_os( ray_solver, object);
  505. IVP_U_Point center(&ray_solver_os.ray_center_point);
  506. m_pMesh->GetAllLedgesWithinRadius( &center, ray_solver_os.ray_length * 0.5f, &ledges );
  507. for (int i=ledges.len()-1;i>=0;i--)
  508. {
  509. const IVP_Compact_Ledge *l = ledges.element_at(i);
  510. ray_solver_os.check_ray_against_compact_ledge_os(l);
  511. }
  512. }
  513. // Used to predict collision detection needs
  514. void IVP_SurfaceManager_VirtualMesh::get_radius_and_radius_dev_to_given_center(const IVP_U_Float_Point *center, IVP_FLOAT *radius, IVP_FLOAT *radius_deviation) const
  515. {
  516. // UNDONE: Check radius_deviation to see if there is a useful optimization to be made here
  517. *radius = m_pMesh->GetSphereRadiusIVP();
  518. *radius_deviation = *radius;
  519. }
  520. // get a single convex if appropriate
  521. const IVP_Compact_Ledge *IVP_SurfaceManager_VirtualMesh::get_single_convex() const
  522. {
  523. return m_pMesh->GetBoundingLedge();
  524. }
  525. // get a mass center for objects using this collision rep
  526. void IVP_SurfaceManager_VirtualMesh::get_mass_center(IVP_U_Float_Point *mass_center_out) const
  527. {
  528. Vector center = m_pMesh->GetMassCenter();
  529. ConvertPositionToIVP( center, *mass_center_out );
  530. }
  531. //-----------------------------------------------------------------------------
  532. // Purpose: Compute a diagonalized inertia tensor.
  533. //-----------------------------------------------------------------------------
  534. void IVP_SurfaceManager_VirtualMesh::get_rotation_inertia( IVP_U_Float_Point *rotation_inertia_out ) const
  535. {
  536. // HACKHACK: No need for this because we only support static objects for now
  537. rotation_inertia_out->set(1,1,1);
  538. }
  539. //-----------------------------------------------------------------------------
  540. // Purpose: Query ledges (triangles in this case) in sphere
  541. //-----------------------------------------------------------------------------
  542. void IVP_SurfaceManager_VirtualMesh::get_all_ledges_within_radius(const IVP_U_Point *observer_os, IVP_DOUBLE radius,
  543. const IVP_Compact_Ledge *root_ledge, IVP_Real_Object *other_object, const IVP_Compact_Ledge *other_reference_ledge,
  544. IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges)
  545. {
  546. if ( !root_ledge )
  547. {
  548. IVP_Compact_Ledge *pLedges[2];
  549. int count = m_pMesh->GetRootLedges( pLedges, ARRAYSIZE(pLedges) );
  550. if ( count )
  551. {
  552. for ( int i = 0; i < count; i++ )
  553. {
  554. resulting_ledges->add( pLedges[i] ); // return the recursive/virtual outer hull
  555. }
  556. return;
  557. }
  558. }
  559. m_pMesh->GetAllLedgesWithinRadius( observer_os, radius, resulting_ledges, root_ledge );
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Purpose: Query all of the ledges (triangles)
  563. //-----------------------------------------------------------------------------
  564. void IVP_SurfaceManager_VirtualMesh::get_all_terminal_ledges(IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges)
  565. {
  566. m_pMesh->GetAllLedges( *resulting_ledges );
  567. }