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.

2474 lines
71 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "cmodel.h"
  10. #include "physics_trace.h"
  11. #include "ivp_surman_polygon.hxx"
  12. #include "ivp_compact_ledge.hxx"
  13. #include "ivp_compact_ledge_solver.hxx"
  14. #include "ivp_compact_surface.hxx"
  15. #include "tier0/vprof.h"
  16. #include "mathlib/ssemath.h"
  17. #include "tier0/tslist.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. // this skips the sphere tree stuff for tracing
  21. #define DEBUG_TEST_ALL_LEDGES 0
  22. // this skips the optimization that shrinks the ray as each intersection is encountered
  23. #define DEBUG_KEEP_FULL_RAY 0
  24. // this skips the optimization that looks up the first vert in a cubemap
  25. #define USE_COLLIDE_MAP 1
  26. // objects with small numbers of verts build a cache of pre-transformed verts
  27. #define USE_VERT_CACHE 1
  28. #define USE_RLE_SPANS 1
  29. // UNDONE: This is a boost on PC, but doesn't work yet on x360 - investigate
  30. #define SIMD_MATRIX 0
  31. // turn this on to get asserts in the low-level collision solver
  32. #define CHECK_TOI_CALCS 0
  33. #define BRUTE_FORCE_VERT_COUNT 128
  34. // NOTE: This is in inches (HL units)
  35. #define TEST_EPSILON (g_PhysicsUnits.collisionSweepIncrementalEpsilon)
  36. struct simplexvert_t
  37. {
  38. Vector position;
  39. unsigned short testIndex : 15;
  40. unsigned short sweepIndex : 1;
  41. unsigned short obstacleIndex;
  42. };
  43. struct simplex_t
  44. {
  45. simplexvert_t verts[4];
  46. int vertCount;
  47. inline bool PointSimplex( const simplexvert_t &newPoint, Vector *pOut );
  48. inline bool EdgeSimplex( const simplexvert_t &newPoint, int outIndex, const Vector &edge, Vector *pOut );
  49. inline bool TriangleSimplex( const simplexvert_t &newPoint, int outIndex, const Vector &faceNormal, Vector *pOut );
  50. bool SolveGJKSet( const simplexvert_t &newPoint, Vector *pOut );
  51. bool SolveVoronoiRegion2( const simplexvert_t &newPoint, Vector *pOut );
  52. bool SolveVoronoiRegion3( const simplexvert_t &newPoint, Vector *pOut );
  53. bool SolveVoronoiRegion4( const simplexvert_t &newPoint, Vector *pOut );
  54. Vector ClipRayToTetrahedronBase( const Vector &dir );
  55. Vector ClipRayToTetrahedron( const Vector &dir );
  56. float ClipRayToTriangle( const Vector &dir, float epsilon );
  57. };
  58. class CTraceCone : public ITraceObject
  59. {
  60. public:
  61. CTraceCone( const truncatedcone_t &cone, const Vector &translation )
  62. {
  63. m_cone = cone;
  64. m_cone.origin += translation;
  65. float cosTheta;
  66. SinCos( DEG2RAD(m_cone.theta), &m_sinTheta, &cosTheta );
  67. m_radius = m_cone.h * m_sinTheta / cosTheta;
  68. m_centerBase = m_cone.origin + m_cone.h * m_cone.normal;
  69. }
  70. virtual int SupportMap( const Vector &dir, Vector *pOut ) const
  71. {
  72. Vector unitDir = dir;
  73. VectorNormalize(unitDir);
  74. float dot = DotProduct( unitDir, m_cone.normal );
  75. // anti-cone is -normal, angle = 90 - theta
  76. // If the normal is in the anti-cone, then return the apex
  77. // not in anti-cone, support map is on the surface of the disc
  78. if ( dot > -m_sinTheta )
  79. {
  80. unitDir -= m_cone.normal * dot;
  81. float len = VectorNormalize( unitDir );
  82. if ( len > 1e-4f )
  83. {
  84. *pOut = m_centerBase + (unitDir * m_radius);
  85. return 0;
  86. }
  87. *pOut = m_centerBase;
  88. return 0;
  89. }
  90. // outside the cone's angle, support map is on the surface of the cone
  91. *pOut = m_cone.origin;
  92. return 0;
  93. }
  94. // BUGBUG: Doesn't work!
  95. virtual Vector GetVertByIndex( int index ) const { return m_cone.origin; }
  96. virtual float Radius( void ) const { return m_cone.h + m_radius; }
  97. truncatedcone_t m_cone;
  98. float m_radius;
  99. float m_sinTheta;
  100. Vector m_centerBase;
  101. };
  102. // really this is indexing a vertex, but the iteration code needs a triangle + edge index.
  103. // edge is always 0-2 so return it in the bottom 2 bits
  104. static unsigned short GetPackedIndex( const IVP_Compact_Ledge *pLedge, const IVP_U_Float_Point &dir )
  105. {
  106. const IVP_Compact_Poly_Point *RESTRICT pPoints = pLedge->get_point_array();
  107. const IVP_Compact_Triangle *RESTRICT pTri = pLedge->get_first_triangle();
  108. const IVP_Compact_Edge *RESTRICT pEdge = pTri->get_edge( 0 );
  109. int best = pEdge->get_start_point_index();
  110. float bestDot = pPoints[best].dot_product( &dir );
  111. int triCount = pLedge->get_n_triangles();
  112. const IVP_Compact_Triangle *RESTRICT pBestTri = pTri;
  113. // this loop will early out, but keep it from being infinite
  114. int i;
  115. // hillclimbing search to find the best support vert
  116. for ( i = 0; i < triCount; i++ )
  117. {
  118. // get the index to the end vert of this edge (start vert on next edge)
  119. pEdge = pEdge->get_prev();
  120. int stopVert = pEdge->get_start_point_index();
  121. // loop through the verts that can be reached along edges from this vert
  122. // stop if you get back to the one you're starting on.
  123. int vert = stopVert;
  124. do
  125. {
  126. float dot = pPoints[vert].dot_product( &dir );
  127. if ( dot > bestDot )
  128. {
  129. bestDot = dot;
  130. best = vert;
  131. pBestTri = pEdge->get_triangle();
  132. break;
  133. }
  134. // tri opposite next edge, same starting vert as next edge
  135. pEdge = pEdge->get_opposite()->get_prev();
  136. vert = pEdge->get_start_point_index();
  137. } while ( vert != stopVert );
  138. // if you exhausted the possibilities for this vert, it must be the best vert
  139. if ( vert != best )
  140. break;
  141. }
  142. int triIndex = pBestTri - pLedge->get_first_triangle();
  143. int edgeIndex = 0;
  144. // just do a search for the edge containing this vert instead of storing it along the way
  145. for ( i = 0; i < 3; i++ )
  146. {
  147. if ( pBestTri->get_edge(i)->get_start_point_index() == best )
  148. {
  149. edgeIndex = i;
  150. break;
  151. }
  152. }
  153. return (unsigned short) ( (triIndex<<2) + edgeIndex );
  154. }
  155. void InitLeafmap( IVP_Compact_Ledge *pLedge, leafmap_t *pLeafmapOut )
  156. {
  157. pLeafmapOut->pLeaf = pLedge;
  158. pLeafmapOut->vertCount = 0;
  159. pLeafmapOut->flags = 0;
  160. pLeafmapOut->spanCount = 0;
  161. if ( pLedge && pLedge->is_terminal() )
  162. {
  163. // for small numbers of verts it's much faster to simply do dot products with all verts
  164. // since the best case for hillclimbing is to touch the start vert plus all neighbors (avg_valence+1 dots)
  165. // in t
  166. int triCount = pLedge->get_n_triangles();
  167. // this is a guess that anything with more than brute_force * 4 tris will have at least brute_force verts
  168. if ( triCount <= BRUTE_FORCE_VERT_COUNT*4 )
  169. {
  170. Assert(triCount>0);
  171. int minV = MAX_CONVEX_VERTS;
  172. int maxV = 0;
  173. for ( int i = 0; i < triCount; i++ )
  174. {
  175. const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
  176. for ( int j = 0; j < 3; j++ )
  177. {
  178. const IVP_Compact_Edge *pEdge = pTri->get_edge( j );
  179. int v = pEdge->get_start_point_index();
  180. if ( v < minV )
  181. {
  182. minV = v;
  183. }
  184. if ( v > maxV )
  185. {
  186. maxV = v;
  187. }
  188. }
  189. }
  190. int vertCount = (maxV-minV) + 1;
  191. // max possible verts is < 48, so this is just here for some real failure
  192. // or vert sharing with a large collection of convexes. In that case the
  193. // number could be high, but this approach to implementing support is invalid
  194. // because the vert range is polluted
  195. if ( vertCount < BRUTE_FORCE_VERT_COUNT )
  196. {
  197. char hasVert[BRUTE_FORCE_VERT_COUNT];
  198. memset(hasVert, 0, sizeof(hasVert[0])*vertCount);
  199. for ( int i = 0; i < triCount; i++ )
  200. {
  201. const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
  202. for ( int j = 0; j < 3; j++ )
  203. {
  204. // mark each vert in the list
  205. const IVP_Compact_Edge *pEdge = pTri->get_edge( j );
  206. int v = pEdge->get_start_point_index();
  207. hasVert[v-minV] = true;
  208. }
  209. }
  210. // now find the vertex spans and encode them
  211. byte spans[BRUTE_FORCE_VERT_COUNT];
  212. int spanIndex = 0;
  213. char has = hasVert[0];
  214. Assert(has);
  215. byte count = 1;
  216. for ( int i = 1; i < vertCount && spanIndex < BRUTE_FORCE_VERT_COUNT; i++ )
  217. {
  218. // each change of state is a new span
  219. if ( has != hasVert[i] )
  220. {
  221. spans[spanIndex] = count;
  222. has = hasVert[i];
  223. count = 0;
  224. spanIndex++;
  225. }
  226. count++;
  227. Assert(count < 255);
  228. }
  229. // rle spans only supported with vertex caching
  230. #if USE_VERT_CACHE && USE_RLE_SPANS
  231. if ( spanIndex < BRUTE_FORCE_VERT_COUNT )
  232. #else
  233. if ( spanIndex < 1 )
  234. #endif
  235. {
  236. spans[spanIndex] = count;
  237. spanIndex++;
  238. pLeafmapOut->SetRLESpans( minV, spanIndex, spans );
  239. }
  240. }
  241. }
  242. }
  243. if ( !pLeafmapOut->HasSpans() )
  244. {
  245. // otherwise make a 8-way directional map to pick the best start vert for hillclimbing
  246. pLeafmapOut->SetHasCubemap();
  247. for ( int i = 0; i < 8; i++ )
  248. {
  249. IVP_U_Float_Point tmp;
  250. tmp.k[0] = ( i & 1 ) ? -1 : 1;
  251. tmp.k[1] = ( i & 2 ) ? -1 : 1;
  252. tmp.k[2] = ( i & 4 ) ? -1 : 1;
  253. pLeafmapOut->startVert[i] = GetPackedIndex( pLedge, tmp );
  254. }
  255. }
  256. }
  257. void GetStartVert( const leafmap_t *pLeafmap, const IVP_U_Float_Point &localDirection, int &triIndex, int &edgeIndex )
  258. {
  259. if ( !pLeafmap || !pLeafmap->HasCubemap() )
  260. return;
  261. // map dir to index
  262. int cacheIndex = (localDirection.k[0] < 0 ? 1 : 0) + (localDirection.k[1] < 0 ? 2 : 0) + (localDirection.k[2] < 0 ? 4 : 0 );
  263. triIndex = pLeafmap->startVert[cacheIndex] >> 2;
  264. edgeIndex = pLeafmap->startVert[cacheIndex] & 0x3;
  265. }
  266. CTSPool<CVisitHash> g_VisitHashPool;
  267. CVisitHash *AllocVisitHash()
  268. {
  269. return g_VisitHashPool.GetObject();
  270. }
  271. void FreeVisitHash(CVisitHash *pFree)
  272. {
  273. if ( pFree )
  274. {
  275. g_VisitHashPool.PutObject(pFree);
  276. }
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose: Implementation for Trace against an IVP object
  280. //-----------------------------------------------------------------------------
  281. class CTraceIVP : public ITraceObject
  282. {
  283. public:
  284. CTraceIVP( const CPhysCollide *pCollide, const Vector &origin, const QAngle &angles );
  285. ~CTraceIVP()
  286. {
  287. if ( m_pVisitHash )
  288. FreeVisitHash(m_pVisitHash);
  289. }
  290. virtual int SupportMap( const Vector &dir, Vector *pOut ) const;
  291. virtual Vector GetVertByIndex( int index ) const;
  292. // UNDONE: Do general ITraceObject center/offset computation and move the ray to account
  293. // for this delta like we do in TraceSweepIVP()
  294. // Then we can shrink the radius of objects with mass centers NOT at the origin
  295. virtual float Radius( void ) const
  296. {
  297. return m_radius;
  298. }
  299. inline float TransformLengthToLocal( float length )
  300. {
  301. return ConvertDistanceToIVP( length );
  302. }
  303. // UNDONE: Optimize this by storing 3 matrices? (one for each transform that includes rot/scale for HL/IVP)?
  304. // UNDONE: Not necessary if we remove the coordinate conversion
  305. inline void TransformDirectionToLocal( const Vector &dir, IVP_U_Float_Point &local ) const
  306. {
  307. IVP_U_Float_Point tmp;
  308. ConvertDirectionToIVP( dir, tmp );
  309. m_matrix.vimult3( &tmp, &local );
  310. }
  311. inline void RotateRelativePositionToLocal( const Vector &delta, IVP_U_Float_Point &local ) const
  312. {
  313. IVP_U_Float_Point tmp;
  314. ConvertPositionToIVP( delta, tmp );
  315. m_matrix.vimult3( &tmp, &local );
  316. }
  317. inline void TransformPositionToLocal( const Vector &pos, IVP_U_Float_Point &local ) const
  318. {
  319. IVP_U_Float_Point tmp;
  320. ConvertPositionToIVP( pos, tmp );
  321. m_matrix.vimult4( &tmp, &local );
  322. }
  323. inline void TransformPositionFromLocal( const IVP_U_Float_Point &local, Vector &out ) const
  324. {
  325. VectorTransform( *(Vector *)&local, *((const matrix3x4_t *)&m_ivpLocalToHLWorld), out );
  326. }
  327. #if USE_VERT_CACHE
  328. inline Vector CachedVertByIndex(int index) const
  329. {
  330. int subIndex = index & 3;
  331. return m_vertCache[index>>2].Vec(subIndex);
  332. }
  333. #endif
  334. bool IsValid( void ) { return m_pLedge != NULL; }
  335. void AllocateVisitHash()
  336. {
  337. if ( !m_pVisitHash )
  338. m_pVisitHash = AllocVisitHash();
  339. }
  340. void SetLedge( const IVP_Compact_Ledge *pLedge )
  341. {
  342. m_pLedge = pLedge;
  343. m_pLeafmap = NULL;
  344. if ( !pLedge )
  345. return;
  346. #if USE_VERT_CACHE
  347. m_cacheCount = 0;
  348. #endif
  349. if ( m_pCollideMap )
  350. {
  351. for ( int i = 0; i < m_pCollideMap->leafCount; i++ )
  352. {
  353. if ( m_pCollideMap->leafmap[i].pLeaf == pLedge )
  354. {
  355. m_pLeafmap = &m_pCollideMap->leafmap[i];
  356. if ( !BuildLeafmapCache( &m_pCollideMap->leafmap[i] ) )
  357. {
  358. AllocateVisitHash();
  359. }
  360. return;
  361. }
  362. }
  363. }
  364. AllocateVisitHash();
  365. }
  366. bool SetSingleConvex( void )
  367. {
  368. const IVP_Compact_Ledgetree_Node *node = m_pSurface->get_compact_ledge_tree_root();
  369. if ( node->is_terminal() == IVP_TRUE )
  370. {
  371. SetLedge( node->get_compact_ledge() );
  372. return true;
  373. }
  374. SetLedge( NULL );
  375. return false;
  376. }
  377. bool BuildLeafmapCache(const leafmap_t * RESTRICT pLeafmap);
  378. bool BuildLeafmapCacheRLE( const leafmap_t * RESTRICT pLeafmap );
  379. inline int SupportMapCached( const Vector &dir, Vector *pOut ) const;
  380. const collidemap_t *m_pCollideMap;
  381. const IVP_Compact_Surface *m_pSurface;
  382. private:
  383. const leafmap_t *m_pLeafmap;
  384. const IVP_Compact_Ledge *m_pLedge;
  385. CVisitHash *m_pVisitHash;
  386. #if SIMD_MATRIX
  387. FourVectors m_ivpLocalToHLWorld;
  388. #else
  389. matrix3x4_t m_ivpLocalToHLWorld;
  390. #endif
  391. IVP_U_Matrix m_matrix;
  392. // transform that includes scale from IVP to HL coords, do not VectorITransform or VectorRotate with this
  393. float m_radius;
  394. int m_nPointTest;
  395. int m_nStartPoint;
  396. bool m_bHasTranslation;
  397. #if USE_VERT_CACHE
  398. int m_cacheCount; // number of FourVectors used
  399. FourVectors m_vertCache[BRUTE_FORCE_VERT_COUNT/4];
  400. #endif
  401. };
  402. // GCC 4.2.1 can't handle loading a static const into a m128 register :(
  403. #ifdef WIN32
  404. static const
  405. #endif
  406. fltx4 g_IVPToHLDir = { 1.0f, -1.0f, 1.0f, 1.0f };
  407. //static const fltx4 g_IVPToHLPosition = { IVP2HL(1.0f), -IVP2HL(1.0f), IVP2HL(1.0f), IVP2HL(1.0f) };
  408. #if defined(_X360)
  409. FORCEINLINE fltx4 ConvertDirectionToIVP( const fltx4 & a )
  410. {
  411. fltx4 t = __vpermwi( a, VPERMWI_CONST( 0, 2, 1, 3 ) );
  412. // negate Y
  413. return MulSIMD( t, g_IVPToHLDir );
  414. }
  415. #else
  416. FORCEINLINE fltx4 ConvertDirectionToIVP( const fltx4 & a )
  417. {
  418. // swap Z & Y
  419. fltx4 t = _mm_shuffle_ps( a, a, MM_SHUFFLE_REV( 0, 2, 1, 3 ) );
  420. // negate Y
  421. return MulSIMD( t, g_IVPToHLDir );
  422. }
  423. #endif
  424. CTraceIVP::CTraceIVP( const CPhysCollide *pCollide, const Vector &origin, const QAngle &angles )
  425. {
  426. #if USE_COLLIDE_MAP
  427. m_pCollideMap = pCollide->GetCollideMap();
  428. #else
  429. m_pCollideMap = NULL;
  430. #endif
  431. m_pSurface = pCollide->GetCompactSurface();
  432. m_pLedge = NULL;
  433. m_pVisitHash = NULL;
  434. m_bHasTranslation = (origin==vec3_origin) ? false : true;
  435. // UNDONE: Move this offset calculation into the tracing routines
  436. // I didn't do this now because it seems to require changes to most of the
  437. // transform routines - and this would cause bugs.
  438. float centerOffset = VectorLength( m_pSurface->mass_center.k );
  439. #if SIMD_MATRIX
  440. VectorAligned forward, right, up;
  441. IVP_U_Float_Point ivpForward, ivpLeft, ivpUp;
  442. AngleVectors( angles, &forward, &right, &up );
  443. Vector left = -right;
  444. Vector down = -up;
  445. ConvertDirectionToIVP( forward, ivpForward );
  446. ConvertDirectionToIVP( left, ivpLeft );
  447. ConvertDirectionToIVP( down, ivpUp );
  448. m_matrix.set_col( IVP_INDEX_X, &ivpForward );
  449. m_matrix.set_col( IVP_INDEX_Z, &ivpLeft );
  450. m_matrix.set_col( IVP_INDEX_Y, &ivpUp );
  451. ConvertPositionToIVP( origin, m_matrix.vv );
  452. forward.w = HL2IVP(origin.x);
  453. // This vector is supposed to be left, so we'll negate it later, but we don't want to
  454. // negate the position, so add another minus to cancel out
  455. right.w = -HL2IVP(origin.y);
  456. up.w = HL2IVP(origin.z);
  457. fltx4 rx = ConvertDirectionToIVP(LoadAlignedSIMD(forward.Base()));
  458. fltx4 ry = ConvertDirectionToIVP(SubSIMD( Four_Zeros, LoadAlignedSIMD(right.Base())) );
  459. fltx4 rz = ConvertDirectionToIVP(LoadAlignedSIMD(up.Base()) );
  460. fltx4 scaleHL = ReplicateX4(IVP2HL(1.0f));
  461. m_ivpLocalToHLWorld.x = MulSIMD( scaleHL, rx );
  462. m_ivpLocalToHLWorld.y = MulSIMD( scaleHL, ry );
  463. m_ivpLocalToHLWorld.z = MulSIMD( scaleHL, rz );
  464. #else
  465. ConvertRotationToIVP( angles, m_matrix );
  466. ConvertPositionToIVP( origin, m_matrix.vv );
  467. float scale = IVP2HL(1.0f);
  468. float negScale = IVP2HL(-1.0f);
  469. // copy the existing IVP local->world matrix (swap Y & Z)
  470. m_ivpLocalToHLWorld.m_flMatVal[0][0] = m_matrix.get_elem(IVP_INDEX_X,0) * scale;
  471. m_ivpLocalToHLWorld.m_flMatVal[0][1] = m_matrix.get_elem(IVP_INDEX_X,1) * scale;
  472. m_ivpLocalToHLWorld.m_flMatVal[0][2] = m_matrix.get_elem(IVP_INDEX_X,2) * scale;
  473. m_ivpLocalToHLWorld.m_flMatVal[1][0] = m_matrix.get_elem(IVP_INDEX_Z,0) * scale;
  474. m_ivpLocalToHLWorld.m_flMatVal[1][1] = m_matrix.get_elem(IVP_INDEX_Z,1) * scale;
  475. m_ivpLocalToHLWorld.m_flMatVal[1][2] = m_matrix.get_elem(IVP_INDEX_Z,2) * scale;
  476. m_ivpLocalToHLWorld.m_flMatVal[2][0] = m_matrix.get_elem(IVP_INDEX_Y,0) * negScale;
  477. m_ivpLocalToHLWorld.m_flMatVal[2][1] = m_matrix.get_elem(IVP_INDEX_Y,1) * negScale;
  478. m_ivpLocalToHLWorld.m_flMatVal[2][2] = m_matrix.get_elem(IVP_INDEX_Y,2) * negScale;
  479. m_ivpLocalToHLWorld.m_flMatVal[0][3] = m_matrix.vv.k[0] * scale;
  480. m_ivpLocalToHLWorld.m_flMatVal[1][3] = m_matrix.vv.k[2] * scale;
  481. m_ivpLocalToHLWorld.m_flMatVal[2][3] = m_matrix.vv.k[1] * negScale;
  482. #endif
  483. m_radius = ConvertDistanceToHL( m_pSurface->upper_limit_radius + centerOffset );
  484. }
  485. bool CTraceIVP::BuildLeafmapCacheRLE( const leafmap_t * RESTRICT pLeafmap )
  486. {
  487. // iterate the rle spans of verts and output them to a buffer in post-transform space
  488. int startPoint = pLeafmap->startVert[0];
  489. int pointCount = pLeafmap->vertCount;
  490. m_cacheCount = (pointCount + 3)>>2;
  491. const byte *RESTRICT pSpans = pLeafmap->GetSpans();
  492. int countThisSpan = pSpans[0];
  493. int spanIndex = 1;
  494. int baseVert = 0;
  495. const VectorAligned * RESTRICT pVerts = (const VectorAligned *)&m_pLedge->get_point_array()[startPoint];
  496. for ( int i = 0; i < m_cacheCount-1; i++ )
  497. {
  498. if ( countThisSpan < 4 )
  499. {
  500. // unrolled for perf
  501. // we need a batch of four verts, but they aren't in a single span
  502. int v0, v1, v2, v3;
  503. if ( !countThisSpan )
  504. {
  505. baseVert += pSpans[spanIndex];
  506. countThisSpan = pSpans[spanIndex+1];
  507. spanIndex += 2;
  508. }
  509. v0 = baseVert++;
  510. countThisSpan--;
  511. if ( !countThisSpan )
  512. {
  513. baseVert += pSpans[spanIndex];
  514. countThisSpan = pSpans[spanIndex+1];
  515. spanIndex += 2;
  516. }
  517. v1 = baseVert++;
  518. countThisSpan--;
  519. if ( !countThisSpan )
  520. {
  521. baseVert += pSpans[spanIndex];
  522. countThisSpan = pSpans[spanIndex+1];
  523. spanIndex += 2;
  524. }
  525. v2 = baseVert++;
  526. countThisSpan--;
  527. if ( !countThisSpan )
  528. {
  529. baseVert += pSpans[spanIndex];
  530. countThisSpan = pSpans[spanIndex+1];
  531. spanIndex += 2;
  532. }
  533. v3 = baseVert++;
  534. countThisSpan--;
  535. m_vertCache[i].LoadAndSwizzleAligned( pVerts[v0].Base(), pVerts[v1].Base(), pVerts[v2].Base(), pVerts[v3].Base() );
  536. }
  537. else
  538. {
  539. // we have four verts in this span, just grab the next four
  540. m_vertCache[i].LoadAndSwizzleAligned( pVerts[baseVert+0].Base(), pVerts[baseVert+1].Base(), pVerts[baseVert+2].Base(), pVerts[baseVert+3].Base() );
  541. baseVert += 4;
  542. countThisSpan -= 4;
  543. }
  544. }
  545. // the last iteration needs multiple spans and clamping to the last vert
  546. int v[4];
  547. for ( int i = 0; i < 4; i++ )
  548. {
  549. if ( spanIndex < pLeafmap->spanCount && !countThisSpan )
  550. {
  551. baseVert += pSpans[spanIndex];
  552. countThisSpan = pSpans[spanIndex+1];
  553. spanIndex += 2;
  554. }
  555. if ( spanIndex < pLeafmap->spanCount )
  556. {
  557. v[i] = baseVert;
  558. baseVert++;
  559. countThisSpan--;
  560. }
  561. else
  562. {
  563. v[i] = baseVert;
  564. if ( countThisSpan > 1 )
  565. {
  566. countThisSpan--;
  567. baseVert++;
  568. }
  569. }
  570. }
  571. m_vertCache[m_cacheCount-1].LoadAndSwizzleAligned( pVerts[v[0]].Base(), pVerts[v[1]].Base(), pVerts[v[2]].Base(), pVerts[v[3]].Base() );
  572. FourVectors::RotateManyBy( &m_vertCache[0], m_cacheCount, *((const matrix3x4_t *)&m_ivpLocalToHLWorld) );
  573. return true;
  574. }
  575. bool CTraceIVP::BuildLeafmapCache( const leafmap_t * RESTRICT pLeafmap )
  576. {
  577. #if !USE_VERT_CACHE
  578. return false;
  579. #else
  580. if ( !pLeafmap || !pLeafmap->HasSpans() || m_bHasTranslation )
  581. return false;
  582. if ( pLeafmap->HasRLESpans() )
  583. {
  584. return BuildLeafmapCacheRLE(pLeafmap);
  585. }
  586. // single vertex span, just xform + copy
  587. // iterate the span of verts and output them to a buffer in post-transform space
  588. // just iterate the range if one is specified
  589. int startPoint = pLeafmap->startVert[0];
  590. int pointCount = pLeafmap->vertCount;
  591. m_cacheCount = (pointCount + 3)>>2;
  592. Assert(m_cacheCount>=0 && m_cacheCount<= (BRUTE_FORCE_VERT_COUNT/4));
  593. const VectorAligned * RESTRICT pVerts = (const VectorAligned *)&m_pLedge->get_point_array()[startPoint];
  594. for ( int i = 0; i < m_cacheCount-1; i++ )
  595. {
  596. m_vertCache[i].LoadAndSwizzleAligned( pVerts[0].Base(), pVerts[1].Base(), pVerts[2].Base(), pVerts[3].Base() );
  597. pVerts += 4;
  598. }
  599. int remIndex = (pointCount-1) & 3;
  600. int x0 = 0;
  601. int x1 = min(1,remIndex);
  602. int x2 = min(2,remIndex);
  603. int x3 = min(3,remIndex);
  604. m_vertCache[m_cacheCount-1].LoadAndSwizzleAligned( pVerts[x0].Base(), pVerts[x1].Base(), pVerts[x2].Base(), pVerts[x3].Base() );
  605. FourVectors::RotateManyBy( &m_vertCache[0], m_cacheCount, *((const matrix3x4_t *)&m_ivpLocalToHLWorld) );
  606. return true;
  607. #endif
  608. }
  609. static const fltx4 g_IndexBase = {0,1,2,3};
  610. int CTraceIVP::SupportMapCached( const Vector &dir, Vector *pOut ) const
  611. {
  612. VPROF("SupportMapCached");
  613. #if USE_VERT_CACHE
  614. FourVectors fourDir;
  615. #if defined(_X360)
  616. fltx4 vec = LoadUnaligned3SIMD( dir.Base() );
  617. fourDir.x = SplatXSIMD(vec);
  618. fourDir.y = SplatYSIMD(vec);
  619. fourDir.z = SplatZSIMD(vec);
  620. #else
  621. fourDir.DuplicateVector(dir);
  622. #endif
  623. fltx4 index = g_IndexBase;
  624. fltx4 maxIndex = g_IndexBase;
  625. fltx4 maxDot = fourDir * m_vertCache[0];
  626. for ( int i = 1; i < m_cacheCount; i++ )
  627. {
  628. index = AddSIMD(index, Four_Fours);
  629. fltx4 dot = fourDir * m_vertCache[i];
  630. fltx4 cmpMask = CmpGtSIMD(dot,maxDot);
  631. maxIndex = MaskedAssign( cmpMask, index, maxIndex );
  632. maxDot = MaxSIMD(dot, maxDot);
  633. }
  634. // find highest of 4
  635. fltx4 rot = RotateLeft2(maxDot);
  636. fltx4 rotIndex = RotateLeft2(maxIndex);
  637. fltx4 cmpMask = CmpGtSIMD(rot,maxDot);
  638. maxIndex = MaskedAssign(cmpMask, rotIndex, maxIndex);
  639. maxDot = MaxSIMD(rot,maxDot);
  640. rotIndex = RotateLeft(maxIndex);
  641. rot = RotateLeft(maxDot);
  642. cmpMask = CmpGtSIMD(rot,maxDot);
  643. maxIndex = MaskedAssign(cmpMask, rotIndex, maxIndex);
  644. // not needed unless we need the actual max dot at the end
  645. // maxDot = MaxSIMD(rot,maxDot);
  646. int bestIndex = SubFloatConvertToInt(maxIndex,0);
  647. *pOut = CachedVertByIndex(bestIndex);
  648. return bestIndex;
  649. #else
  650. Assert(0);
  651. #endif
  652. }
  653. int CTraceIVP::SupportMap( const Vector &dir, Vector *pOut ) const
  654. {
  655. #if USE_VERT_CACHE
  656. if ( m_cacheCount )
  657. return SupportMapCached( dir, pOut );
  658. #endif
  659. if ( m_pLeafmap && m_pLeafmap->HasSingleVertexSpan() )
  660. {
  661. VPROF("SupportMap_Leaf");
  662. const IVP_U_Float_Point *pPoints = m_pLedge->get_point_array();
  663. IVP_U_Float_Point mapdir;
  664. TransformDirectionToLocal( dir, mapdir );
  665. // just iterate the range if one is specified
  666. int startPoint = m_pLeafmap->startVert[0];
  667. int pointCount = m_pLeafmap->vertCount;
  668. float bestDot = pPoints[startPoint].dot_product(&mapdir);
  669. int best = startPoint;
  670. for ( int i = 1; i < pointCount; i++ )
  671. {
  672. float dot = pPoints[startPoint+i].dot_product(&mapdir);
  673. if ( dot > bestDot )
  674. {
  675. bestDot = dot;
  676. best = startPoint+i;
  677. }
  678. }
  679. TransformPositionFromLocal( pPoints[best], *pOut ); // transform point position to world space
  680. return best;
  681. }
  682. else
  683. {
  684. VPROF("SupportMap_Walk");
  685. const IVP_U_Float_Point *pPoints = m_pLedge->get_point_array();
  686. IVP_U_Float_Point mapdir;
  687. TransformDirectionToLocal( dir, mapdir );
  688. int triCount = m_pLedge->get_n_triangles();
  689. Assert( m_pVisitHash );
  690. m_pVisitHash->NewVisit();
  691. float dot;
  692. int triIndex = 0, edgeIndex = 0;
  693. GetStartVert( m_pLeafmap, mapdir, triIndex, edgeIndex );
  694. const IVP_Compact_Triangle *RESTRICT pTri = m_pLedge->get_first_triangle() + triIndex;
  695. const IVP_Compact_Edge *RESTRICT pEdge = pTri->get_edge( edgeIndex );
  696. int best = pEdge->get_start_point_index();
  697. float bestDot = pPoints[best].dot_product( &mapdir );
  698. m_pVisitHash->VisitVert(best);
  699. // This should never happen. MAX_CONVEX_VERTS is very large (millions), none of our
  700. // models have anywhere near this many verts in a convex piece
  701. Assert(triCount*3<MAX_CONVEX_VERTS);
  702. // this loop will early out, but keep it from being infinite
  703. for ( int i = 0; i < triCount; i++ )
  704. {
  705. // get the index to the end vert of this edge (start vert on next edge)
  706. pEdge = pEdge->get_prev();
  707. int stopVert = pEdge->get_start_point_index();
  708. // loop through the verts that can be reached along edges from this vert
  709. // stop if you get back to the one you're starting on.
  710. int vert = stopVert;
  711. do
  712. {
  713. if ( !m_pVisitHash->WasVisited(vert) )
  714. {
  715. // this lets us skip doing dot products on this vert
  716. m_pVisitHash->VisitVert(vert);
  717. dot = pPoints[vert].dot_product( &mapdir );
  718. if ( dot > bestDot )
  719. {
  720. bestDot = dot;
  721. best = vert;
  722. break;
  723. }
  724. }
  725. // tri opposite next edge, same starting vert as next edge
  726. pEdge = pEdge->get_opposite()->get_prev();
  727. vert = pEdge->get_start_point_index();
  728. } while ( vert != stopVert );
  729. // if you exhausted the possibilities for this vert, it must be the best vert
  730. if ( vert != best )
  731. break;
  732. }
  733. // code to do the brute force method with no hill-climbing
  734. #if 0
  735. for ( i = 0; i < triCount; i++ )
  736. {
  737. pTri = m_pLedge->get_first_triangle() + i;
  738. for ( int j = 0; j < 3; j++ )
  739. {
  740. pEdge = pTri->get_edge( j );
  741. int test = pEdge->get_start_point_index();
  742. dot = pPoints[test].dot_product( &mapdir );
  743. if ( dot > bestDot )
  744. {
  745. Assert(0); // shouldn't hit this unless the hill-climb is broken
  746. bestDot = dot;
  747. best = test;
  748. }
  749. }
  750. }
  751. #endif
  752. TransformPositionFromLocal( pPoints[best], *pOut ); // transform point position to world space
  753. return best;
  754. }
  755. }
  756. Vector CTraceIVP::GetVertByIndex( int index ) const
  757. {
  758. #if USE_VERT_CACHE
  759. if ( m_cacheCount )
  760. {
  761. return CachedVertByIndex(index);
  762. }
  763. #endif
  764. const IVP_Compact_Poly_Point *pPoints = m_pLedge->get_point_array();
  765. Vector out;
  766. TransformPositionFromLocal( pPoints[index], out );
  767. return out;
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Purpose: Implementation for Trace against an AABB
  771. //-----------------------------------------------------------------------------
  772. class CTraceAABB : public ITraceObject
  773. {
  774. public:
  775. CTraceAABB( const Vector &hlmins, const Vector &hlmaxs, bool isPoint );
  776. virtual int SupportMap( const Vector &dir, Vector *pOut ) const;
  777. virtual Vector GetVertByIndex( int index ) const;
  778. virtual float Radius( void ) const { return m_radius; }
  779. private:
  780. float m_x[2];
  781. float m_y[2];
  782. float m_z[2];
  783. float m_radius;
  784. bool m_empty;
  785. };
  786. CTraceAABB::CTraceAABB( const Vector &hlmins, const Vector &hlmaxs, bool isPoint )
  787. {
  788. if ( isPoint )
  789. {
  790. m_x[0] = m_x[1] = 0;
  791. m_y[0] = m_y[1] = 0;
  792. m_z[0] = m_z[1] = 0;
  793. m_radius = 0;
  794. m_empty = true;
  795. }
  796. else
  797. {
  798. m_x[0] = hlmaxs[0];
  799. m_x[1] = hlmins[0];
  800. m_y[0] = hlmaxs[1];
  801. m_y[1] = hlmins[1];
  802. m_z[0] = hlmaxs[2];
  803. m_z[1] = hlmins[2];
  804. m_radius = hlmaxs.Length();
  805. m_empty = false;
  806. }
  807. }
  808. int CTraceAABB::SupportMap( const Vector &dir, Vector *pOut ) const
  809. {
  810. Vector out;
  811. if ( m_empty )
  812. {
  813. pOut->Init();
  814. return 0;
  815. }
  816. // index is formed by the 3-bit bitfield SzSySx (negative is 1, positive is 0)
  817. int x = ((*((unsigned int *)&dir.x)) & 0x80000000UL) >> 31;
  818. int y = ((*((unsigned int *)&dir.y)) & 0x80000000UL) >> 31;
  819. int z = ((*((unsigned int *)&dir.z)) & 0x80000000UL) >> 31;
  820. pOut->x = m_x[x];
  821. pOut->y = m_y[y];
  822. pOut->z = m_z[z];
  823. return (z<<2) | (y<<1) | x;
  824. }
  825. Vector CTraceAABB::GetVertByIndex( int index ) const
  826. {
  827. Vector out;
  828. out.x = m_x[(index&1)];
  829. out.y = m_y[(index&2)>>1];
  830. out.z = m_z[(index&4)>>2];
  831. return out;
  832. }
  833. //-----------------------------------------------------------------------------
  834. // Purpose: Implementation for Trace against an IVP object
  835. //-----------------------------------------------------------------------------
  836. class CTraceRay
  837. {
  838. public:
  839. CTraceRay( const Vector &hlstart, const Vector &hlend );
  840. CTraceRay( const Ray_t &ray );
  841. CTraceRay( const Ray_t &ray, const Vector &offset );
  842. void Init( const Vector &hlstart, const Vector &delta );
  843. int SupportMap( const Vector &dir, Vector *pOut ) const;
  844. Vector GetVertByIndex( int index ) const { return ( index ) ? m_end : m_start; }
  845. float Radius( void ) const { return m_length * 0.5f; }
  846. void Reset( float fraction );
  847. Vector m_start;
  848. Vector m_end;
  849. Vector m_delta;
  850. Vector m_dir;
  851. float m_length;
  852. float m_baseLength;
  853. float m_ooBaseLength;
  854. float m_bestDist;
  855. };
  856. CTraceRay::CTraceRay( const Vector &hlstart, const Vector &hlend )
  857. {
  858. Init(hlstart, hlend-hlstart);
  859. }
  860. void CTraceRay::Init( const Vector &hlstart, const Vector &delta )
  861. {
  862. m_start = hlstart;
  863. m_end = hlstart + delta;
  864. m_delta = delta;
  865. m_dir = delta;
  866. float len = DotProduct(delta, delta);
  867. // don't use fast/sse sqrt here we need the precision
  868. m_length = sqrt(len);
  869. m_ooBaseLength = 0.0f;
  870. if ( m_length > 0 )
  871. {
  872. m_ooBaseLength = 1.0f / m_length;
  873. m_dir *= m_ooBaseLength;
  874. }
  875. m_baseLength = m_length;
  876. m_bestDist = 0.f;
  877. }
  878. CTraceRay::CTraceRay( const Ray_t &ray )
  879. {
  880. Init( ray.m_Start, ray.m_Delta );
  881. }
  882. CTraceRay::CTraceRay( const Ray_t &ray, const Vector &offset )
  883. {
  884. Vector start;
  885. VectorAdd( ray.m_Start, offset, start );
  886. Init( start, ray.m_Delta );
  887. }
  888. void CTraceRay::Reset( float fraction )
  889. {
  890. // recompute from base values for max precision
  891. m_length = m_baseLength * fraction;
  892. m_end = m_start + fraction * m_delta;
  893. m_bestDist = 0.f;
  894. }
  895. int CTraceRay::SupportMap( const Vector &dir, Vector *pOut ) const
  896. {
  897. if ( DotProduct( dir, m_delta ) > 0 )
  898. {
  899. *pOut = m_end;
  900. return 1;
  901. }
  902. *pOut = m_start;
  903. return 0;
  904. }
  905. static char *map_nullname = "**empty**";
  906. static csurface_t nullsurface = { map_nullname, 0 };
  907. static void CM_ClearTrace( trace_t *trace )
  908. {
  909. memset( trace, 0, sizeof(*trace));
  910. trace->fraction = 1.f;
  911. trace->fractionleftsolid = 0;
  912. trace->surface = nullsurface;
  913. }
  914. class CDefConvexInfo : public IConvexInfo
  915. {
  916. public:
  917. IConvexInfo *GetPtr() { return this; }
  918. virtual unsigned int GetContents( int convexGameData ) { return CONTENTS_SOLID; }
  919. };
  920. class CTraceSolver
  921. {
  922. public:
  923. CTraceSolver( trace_t *ptr, ITraceObject *sweepobject, CTraceRay *ray, ITraceObject *obstacle, const Vector &axis )
  924. {
  925. m_pTotalTrace = ptr;
  926. m_sweepObject = sweepobject;
  927. m_sweepObjectRadius = m_sweepObject->Radius();
  928. m_obstacle = obstacle;
  929. m_ray = ray;
  930. m_traceLength = 0;
  931. m_totalTraceLength = max( ray->m_baseLength, 1e-8f );
  932. m_pointClosestToIntersection = axis;
  933. m_epsilon = g_PhysicsUnits.collisionSweepEpsilon;
  934. }
  935. bool SweepSingleConvex( void );
  936. float SolveMeshIntersection( simplex_t &simplex );
  937. float SolveMeshIntersection2D( simplex_t &simplex );
  938. virtual void DoSweep( void )
  939. {
  940. SweepSingleConvex();
  941. *m_pTotalTrace = m_trace;
  942. }
  943. void SetEpsilon( float epsilon )
  944. {
  945. m_epsilon = epsilon;
  946. }
  947. protected:
  948. trace_t m_trace;
  949. Vector m_pointClosestToIntersection;
  950. ITraceObject *m_sweepObject;
  951. ITraceObject *m_obstacle;
  952. CTraceRay *m_ray;
  953. trace_t *m_pTotalTrace;
  954. float m_traceLength;
  955. float m_totalTraceLength;
  956. float m_sweepObjectRadius;
  957. float m_epsilon;
  958. private:
  959. CTraceSolver( const CTraceSolver & );
  960. };
  961. class CTraceSolverSweptObject : public CTraceSolver
  962. {
  963. public:
  964. CTraceSolverSweptObject( trace_t *ptr, ITraceObject *sweepobject, CTraceRay *ray, CTraceIVP *obstacle, const Vector &axis, unsigned int contentsMask, IConvexInfo *pConvexInfo );
  965. void InitOSRay( void );
  966. void SweepLedgeTree_r( const IVP_Compact_Ledgetree_Node *node );
  967. inline bool SweepHitsSphereOS( const IVP_U_Float_Point *sphereCenter, float radius );
  968. virtual void DoSweep( void );
  969. inline void SweepAgainstNode( const IVP_Compact_Ledgetree_Node *node );
  970. CTraceIVP *m_obstacleIVP;
  971. IConvexInfo *m_pConvexInfo;
  972. unsigned int m_contentsMask;
  973. CDefConvexInfo m_fakeConvexInfo;
  974. IVP_U_Float_Point m_rayCenterOS;
  975. IVP_U_Float_Point m_rayStartOS;
  976. IVP_U_Float_Point m_rayDirOS;
  977. IVP_U_Float_Point m_rayDeltaOS;
  978. float m_rayLengthOS;
  979. private:
  980. CTraceSolverSweptObject( const CTraceSolverSweptObject & ); // no implementation, quells compiler warning
  981. };
  982. CTraceSolverSweptObject::CTraceSolverSweptObject( trace_t *ptr, ITraceObject *sweepobject, CTraceRay *ray, CTraceIVP *obstacle, const Vector &axis, unsigned int contentsMask, IConvexInfo *pConvexInfo )
  983. : CTraceSolver( ptr, sweepobject, ray, obstacle, axis )
  984. {
  985. m_obstacleIVP = obstacle;
  986. m_contentsMask = contentsMask;
  987. m_pConvexInfo = (pConvexInfo != NULL) ? pConvexInfo : m_fakeConvexInfo.GetPtr();
  988. }
  989. bool CTraceSolverSweptObject::SweepHitsSphereOS( const IVP_U_Float_Point *sphereCenter, float radius )
  990. {
  991. // disable this to help find bugs
  992. #if DEBUG_TEST_ALL_LEDGES
  993. return true;
  994. #endif
  995. // the ray is actually a line-swept-sphere with sweep object's radius
  996. IVP_U_Float_Point delta_vec; // quick check for ends of ray
  997. delta_vec.subtract( sphereCenter, &m_rayCenterOS );
  998. radius += m_sweepObjectRadius;
  999. // Is the sphere close enough to the ray at the center?
  1000. float qsphere_rad = radius * radius;
  1001. // If this is a 0 length ray, then the conservative test is 100% accurate
  1002. if ( m_rayLengthOS > 0 )
  1003. {
  1004. // Calculate the perpendicular distance to the sphere
  1005. // The perpendicular forms a right triangle with the vector between the ray/sphere centers
  1006. // and the ray direction vector. Calculate the projection of the hypoteneuse along the perpendicular
  1007. IVP_U_Float_Point h;
  1008. h.inline_calc_cross_product(&m_rayDirOS, &delta_vec);
  1009. if( h.quad_length() < qsphere_rad )
  1010. return true;
  1011. }
  1012. else
  1013. {
  1014. float quad_center_dist = delta_vec.quad_length();
  1015. if ( quad_center_dist < qsphere_rad )
  1016. {
  1017. return true;
  1018. }
  1019. // Could a ray in any direction away from the ray center intersect this sphere?
  1020. float qrad_sum = m_rayLengthOS * 0.5f + radius;
  1021. qrad_sum *= qrad_sum;
  1022. if ( quad_center_dist >= qrad_sum )
  1023. {
  1024. return false;
  1025. }
  1026. }
  1027. return false;
  1028. }
  1029. inline void CTraceSolverSweptObject::SweepAgainstNode(const IVP_Compact_Ledgetree_Node *node)
  1030. {
  1031. const IVP_Compact_Ledge *ledge = node->get_compact_ledge();
  1032. unsigned int ledgeContents = m_pConvexInfo->GetContents( ledge->get_client_data() );
  1033. if (m_contentsMask & ledgeContents)
  1034. {
  1035. m_obstacleIVP->SetLedge( ledge );
  1036. if ( SweepSingleConvex() )
  1037. {
  1038. if ( m_traceLength < m_totalTraceLength )
  1039. {
  1040. m_pTotalTrace->plane.normal = m_trace.plane.normal;
  1041. m_pTotalTrace->startsolid = m_trace.startsolid;
  1042. m_pTotalTrace->allsolid = m_trace.allsolid;
  1043. m_totalTraceLength = m_traceLength;
  1044. m_pTotalTrace->fraction = m_traceLength * m_ray->m_ooBaseLength;
  1045. Assert(m_pTotalTrace->fraction >= 0 && m_pTotalTrace->fraction <= 1.0f);
  1046. #if !DEBUG_KEEP_FULL_RAY
  1047. // shrink the ray to the shortened length, but leave a buffer of collisionSweepEpsilon units
  1048. // at the end to make sure that precision doesn't make you miss something slightly closer
  1049. float testFraction = (m_traceLength + m_epsilon*2) * m_ray->m_ooBaseLength;
  1050. if ( testFraction < 1.0f )
  1051. {
  1052. m_ray->Reset( testFraction );
  1053. // Update OS ray to limit tests
  1054. m_rayLengthOS = m_obstacleIVP->TransformLengthToLocal( m_ray->m_length );
  1055. m_rayCenterOS.add_multiple( &m_rayStartOS, &m_rayDeltaOS, 0.5f * testFraction );
  1056. }
  1057. #endif
  1058. m_pTotalTrace->contents = ledgeContents;
  1059. }
  1060. }
  1061. }
  1062. }
  1063. void CTraceSolverSweptObject::SweepLedgeTree_r( const IVP_Compact_Ledgetree_Node *node )
  1064. {
  1065. IVP_U_Float_Point center;
  1066. center.set(node->center.k);
  1067. if ( !SweepHitsSphereOS( &center, node->radius ) )
  1068. return;
  1069. // fast path for single leaf collision models
  1070. if ( node->is_terminal() == IVP_TRUE )
  1071. {
  1072. SweepAgainstNode(node);
  1073. return;
  1074. }
  1075. // use an array to implement a simple stack
  1076. CUtlVectorFixedGrowable<const IVP_Compact_Ledgetree_Node *, 64> list;
  1077. // pull the last item in the array (top of stack)
  1078. // this is nearly a priority queue, but not actually, but it's cheaper (and faster in the benchmarks)
  1079. // this code is trying to visit the nodes closest to the ray start first - which helps performance
  1080. // since we're only interested in the first intersection of the swept object with the physcollide.
  1081. while ( 1 )
  1082. {
  1083. // don't use the temp storage unless you have to.
  1084. loop_without_store:
  1085. if ( node->is_terminal() == IVP_TRUE )
  1086. {
  1087. // leaf, do the test
  1088. SweepAgainstNode(node);
  1089. }
  1090. else
  1091. {
  1092. // check node's children
  1093. const IVP_Compact_Ledgetree_Node *node0 = node->left_son();
  1094. center.set(node0->center.k);
  1095. // if we don't insert, this is larger than any quad distance
  1096. float lastDist = 1e24f;
  1097. if ( SweepHitsSphereOS( &center, node0->radius ) )
  1098. {
  1099. lastDist = m_rayStartOS.quad_distance_to(&center);
  1100. }
  1101. else
  1102. {
  1103. node0 = NULL;
  1104. }
  1105. const IVP_Compact_Ledgetree_Node *node1 = node->right_son();
  1106. center.set(node1->center.k);
  1107. if ( SweepHitsSphereOS( &center, node1->radius ) )
  1108. {
  1109. if ( node0 )
  1110. {
  1111. // can hit, push on stack
  1112. int index = list.AddToTail();
  1113. float dist1 = m_rayStartOS.quad_distance_to(&center);
  1114. if ( lastDist < dist1 )
  1115. {
  1116. node = node0;
  1117. list[index] = node1;
  1118. }
  1119. else
  1120. {
  1121. node = node1;
  1122. list[index] = node0;
  1123. }
  1124. }
  1125. else
  1126. {
  1127. node = node1;
  1128. }
  1129. goto loop_without_store;
  1130. }
  1131. if ( node0 )
  1132. {
  1133. node = node0;
  1134. goto loop_without_store;
  1135. }
  1136. }
  1137. int last = list.Count()-1;
  1138. if ( last < 0 )
  1139. break;
  1140. node = list[last];
  1141. list.FastRemove(last);
  1142. }
  1143. }
  1144. void CTraceSolverSweptObject::InitOSRay( void )
  1145. {
  1146. // transform ray into object space
  1147. m_rayLengthOS = m_obstacleIVP->TransformLengthToLocal( m_ray->m_length );
  1148. m_obstacleIVP->TransformPositionToLocal( m_ray->m_start, m_rayStartOS );
  1149. // no translation on matrix mult because this is a vector
  1150. m_obstacleIVP->RotateRelativePositionToLocal( m_ray->m_delta, m_rayDeltaOS );
  1151. m_rayDirOS.set(&m_rayDeltaOS);
  1152. m_rayDirOS.normize();
  1153. // add_multiple with 3 params assumes no initial value (should be set_add_multiple)
  1154. m_rayCenterOS.add_multiple( &m_rayStartOS, &m_rayDeltaOS, 0.5f );
  1155. }
  1156. void CTraceSolverSweptObject::DoSweep( void )
  1157. {
  1158. VPROF("TraceSolver::DoSweep");
  1159. InitOSRay();
  1160. // iterate ledge tree of obstacle
  1161. const IVP_Compact_Surface *pSurface = m_obstacleIVP->m_pSurface;
  1162. const IVP_Compact_Ledgetree_Node *lt_node_root;
  1163. lt_node_root = pSurface->get_compact_ledge_tree_root();
  1164. SweepLedgeTree_r( lt_node_root );
  1165. }
  1166. void CPhysicsTrace::SweepBoxIVP( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &surfaceOrigin, const QAngle &surfaceAngles, trace_t *ptr )
  1167. {
  1168. Ray_t ray;
  1169. ray.Init( start, end, mins, maxs );
  1170. SweepBoxIVP( ray, MASK_ALL, NULL, pCollide, surfaceOrigin, surfaceAngles, ptr );
  1171. }
  1172. void CPhysicsTrace::SweepBoxIVP( const Ray_t &raySrc, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &surfaceOrigin, const QAngle &surfaceAngles, trace_t *ptr )
  1173. {
  1174. CM_ClearTrace( ptr );
  1175. CTraceAABB box( -raySrc.m_Extents, raySrc.m_Extents, raySrc.m_IsRay );
  1176. CTraceIVP ivp( pCollide, vec3_origin, surfaceAngles );
  1177. // offset the space of this sweep so that the surface is at the origin of the solution space
  1178. CTraceRay ray( raySrc, -surfaceOrigin );
  1179. CTraceSolverSweptObject solver( ptr, &box, &ray, &ivp, ray.m_start, contentsMask, pConvexInfo );
  1180. solver.DoSweep();
  1181. VectorAdd( raySrc.m_Start, raySrc.m_StartOffset, ptr->startpos );
  1182. VectorMA( ptr->startpos, ptr->fraction, raySrc.m_Delta, ptr->endpos );
  1183. // The plane was shifted because we shifted everything over by surfaceOrigin, shift it back
  1184. if ( ptr->DidHit() )
  1185. {
  1186. ptr->plane.dist = DotProduct( ptr->endpos, ptr->plane.normal );
  1187. }
  1188. }
  1189. void CPhysicsTrace::SweepIVP( const Vector &start, const Vector &end, const CPhysCollide *pSweptSurface, const QAngle &sweptAngles, const CPhysCollide *pSurface, const Vector &surfaceOrigin, const QAngle &surfaceAngles, trace_t *ptr )
  1190. {
  1191. CM_ClearTrace( ptr );
  1192. CTraceIVP sweptObject( pSweptSurface, vec3_origin, sweptAngles );
  1193. // offset the space of this sweep so that the surface is at the origin of the solution space
  1194. CTraceIVP ivp( pSurface, vec3_origin, surfaceAngles );
  1195. CTraceRay ray( start - surfaceOrigin, end - surfaceOrigin );
  1196. IVP_U_BigVector<IVP_Compact_Ledge> objectLedges(32);
  1197. IVP_Compact_Ledge_Solver::get_all_ledges( pSweptSurface->GetCompactSurface(), &objectLedges );
  1198. for ( int i = objectLedges.len() - 1; i >= 0; --i )
  1199. {
  1200. trace_t tr;
  1201. CM_ClearTrace( &tr );
  1202. sweptObject.SetLedge( objectLedges.element_at(i) );
  1203. CTraceSolverSweptObject solver( &tr, &sweptObject, &ray, &ivp, start - surfaceOrigin, MASK_ALL, NULL );
  1204. // UNDONE: Need just more than 0.25" tolerance here because the output position will be used by vphysics
  1205. // UNDONE: Really this should be the collision radius from the environment.
  1206. solver.SetEpsilon( g_PhysicsUnits.globalCollisionTolerance );
  1207. solver.DoSweep();
  1208. if ( tr.fraction < ptr->fraction )
  1209. {
  1210. *ptr = tr;
  1211. }
  1212. }
  1213. ptr->endpos = start*(1.f-ptr->fraction) + end * ptr->fraction;
  1214. if ( ptr->DidHit() )
  1215. {
  1216. ptr->plane.dist = DotProduct( ptr->endpos, ptr->plane.normal );
  1217. }
  1218. }
  1219. static void CalculateSeparatingPlane( trace_t *ptr, ITraceObject *sweepObject, CTraceRay *ray, ITraceObject *obstacle, simplex_t &simplex );
  1220. //-----------------------------------------------------------------------------
  1221. // What is this doing? It's going to be hard to understand without reading a
  1222. // reference on the GJK algorithm. But here's a quick overview:
  1223. // Basically (remember this is glossing over a ton of details!) the
  1224. // algorithm is building up a simplex that is trying to contain the origin.
  1225. // A simplex is a point, line segment, triangle, or tetrahedron - depending on
  1226. // how many verts you have.
  1227. // Anyway it slowly builds one of these one vert at a time with a directed search.
  1228. // So you start out with a point, then it guesses the next point that would be
  1229. // most likely to form a line through the origin. If the line doesn't go quite
  1230. // through the origin it tries to find a third point to capture the origin
  1231. // within a triangle. If that doesn't work it tries to make a
  1232. // tent (tetrahedron) out of the triangle to capture the origin.
  1233. //
  1234. // But at each step if the origin is not contained within, it tries to
  1235. // find which sub-feature is most likely to be in the solution. In
  1236. // the point case it's always just the point. In the line/edge case it
  1237. // can reduce back to a point (origin is closest to one of the points)
  1238. // or be the line (origin is closest to some point between them).
  1239. // Same with the triangle (origin is closest to one vert - vert, origin is
  1240. // closest to one edge - reduce to that edge, origin is closes to some point
  1241. // in the triangle's surface - keep the whole triangle). With a tetrahedron
  1242. // keeping the whole isn't possible unless the origin is inside and you're
  1243. // done (the origin has been captured).
  1244. //
  1245. // "You're done" means that there is an intersection between the two
  1246. // volumes. Assuming you're testing a sweep, it still has to test whether that
  1247. // sweep can be shrunk back until there is no intersection. So it checks that.
  1248. // If it's a swept test so it does the search with SolveMeshIntersection
  1249. // Otherwise, there's nothing to shrink, so you set startsolid and allsolid
  1250. // because it's a point/box in solid test, not a swept box/ray hits solid test.
  1251. //
  1252. // Why is it trying to capture the origin? Basically GJK sets up a space
  1253. // and a convex hull (the minkowski sum) in that space. The convex hull
  1254. // represents a field of the distances between different features of the pair
  1255. // of objects (e.g. for two circles, this minkowski sum is just a circle).
  1256. // So the origin is the point in the field where the distance between the
  1257. // objects is zero. This means they intersect.
  1258. //-----------------------------------------------------------------------------
  1259. #if defined(_X360)
  1260. inline void VectorNormalize_FastLowPrecision( Vector &a )
  1261. {
  1262. float quad = (a.x*a.x) + (a.y*a.y) + (a.z*a.z);
  1263. float ilen = __frsqrte(quad);
  1264. a.x *= ilen;
  1265. a.y *= ilen;
  1266. a.z *= ilen;
  1267. }
  1268. #else
  1269. #define VectorNormalize_FastLowPrecision VectorNormalize
  1270. #endif
  1271. bool CTraceSolver::SweepSingleConvex( void )
  1272. {
  1273. VPROF("TraceSolver::SweepSingleConvex");
  1274. simplex_t simplex;
  1275. simplexvert_t vert;
  1276. Vector tmp;
  1277. simplex.vertCount = 0;
  1278. if ( m_pointClosestToIntersection == vec3_origin )
  1279. {
  1280. m_pointClosestToIntersection.Init(1,0,0);
  1281. }
  1282. float testLen = 1;
  1283. Vector dir = -m_pointClosestToIntersection;
  1284. VectorNormalize_FastLowPrecision(dir);
  1285. // safe loop, max 100 iterations
  1286. for ( int i = 0; i < 100; i++ )
  1287. {
  1288. // map the direction into the minkowski sum, get a new surface point
  1289. vert.testIndex = m_sweepObject->SupportMap( dir, &vert.position );
  1290. vert.sweepIndex = m_ray->SupportMap( dir, &tmp );
  1291. VectorAdd( vert.position, tmp, vert.position );
  1292. vert.obstacleIndex = m_obstacle->SupportMap( -dir, &tmp );
  1293. VectorSubtract( vert.position, tmp, vert.position );
  1294. testLen = DotProduct( dir, vert.position );
  1295. // found a separating axis, no intersection
  1296. if ( testLen < 0 )
  1297. {
  1298. VPROF("SolveSeparation");
  1299. // make sure we're separated by at least m_epsilon
  1300. testLen = fabs(testLen);
  1301. if ( testLen < m_epsilon && m_ray->m_length > 0 )
  1302. {
  1303. // not separated by enough
  1304. Vector normal = dir;
  1305. if ( testLen > 0 )
  1306. {
  1307. // try to find a better separating plane or clip the ray to the current one
  1308. for ( int j = 0; j < 20; j++ )
  1309. {
  1310. Vector lastVert = vert.position;
  1311. simplex.SolveGJKSet( vert, &m_pointClosestToIntersection );
  1312. dir = -m_pointClosestToIntersection;
  1313. VectorNormalize_FastLowPrecision( dir );
  1314. // map the direction into the minkowski sum, get a new surface point
  1315. vert.testIndex = m_sweepObject->SupportMap( dir, &vert.position );
  1316. vert.sweepIndex = m_ray->SupportMap( dir, &tmp );
  1317. VectorAdd( vert.position, tmp, vert.position );
  1318. vert.obstacleIndex = m_obstacle->SupportMap( -dir, &tmp );
  1319. VectorSubtract( vert.position, tmp, vert.position );
  1320. // found a separating axis, no intersection
  1321. float est = -DotProduct( dir, vert.position );
  1322. if ( est > m_epsilon ) // big enough separation, no hit
  1323. return false;
  1324. // take plane with the most separation
  1325. if ( est > testLen )
  1326. {
  1327. testLen = est;
  1328. normal = dir;
  1329. }
  1330. float last = -DotProduct( dir, lastVert );
  1331. // search is not converging, exit.
  1332. if ( (est - last) > -1e-4f )
  1333. break;
  1334. }
  1335. }
  1336. // This trace is going to miss, but not by enough.
  1337. // Hit the separating plane instead
  1338. float dot = -DotProduct( m_ray->m_delta, normal );
  1339. if ( dot < -(m_epsilon*0.1) || (dot < -1e-4f && testLen < (m_epsilon*0.9)) )
  1340. {
  1341. CM_ClearTrace( &m_trace );
  1342. float backupDistance = m_epsilon - testLen;
  1343. backupDistance = -(backupDistance * m_ray->m_baseLength) / dot;
  1344. m_traceLength = m_ray->m_length - backupDistance;
  1345. if ( m_traceLength < 0 )
  1346. {
  1347. m_traceLength = 0;
  1348. // try sliding along the surface of the minkowski sum
  1349. backupDistance = SolveMeshIntersection2D( simplex );
  1350. if ( m_ray->m_length > backupDistance )
  1351. {
  1352. m_traceLength = m_ray->m_length - backupDistance;
  1353. }
  1354. }
  1355. m_trace.plane.normal = -normal;
  1356. // this is fixed up by the outer code
  1357. //m_trace.endpos = m_ray->m_start*(1.f-m_trace.fraction) + m_ray->m_end*m_trace.fraction;
  1358. m_trace.contents = CONTENTS_SOLID;
  1359. return true;
  1360. }
  1361. }
  1362. return false;
  1363. }
  1364. // contains the origin
  1365. if ( simplex.SolveGJKSet( vert, &m_pointClosestToIntersection ) )
  1366. {
  1367. VPROF("TraceSolver::SolveMeshIntersection");
  1368. CM_ClearTrace( &m_trace );
  1369. // now solve for t along the sweep
  1370. if ( m_ray->m_length != 0 )
  1371. {
  1372. float dist = SolveMeshIntersection( simplex );
  1373. if ( dist < m_ray->m_length && dist > 0.f )
  1374. {
  1375. m_traceLength = (m_ray->m_length - dist);
  1376. CalculateSeparatingPlane( &m_trace, m_sweepObject, m_ray, m_obstacle, simplex );
  1377. float dot = DotProduct( m_ray->m_dir, m_trace.plane.normal );
  1378. if ( dot < 0 )
  1379. {
  1380. m_traceLength += (m_epsilon / dot);
  1381. }
  1382. if ( m_traceLength < 0 )
  1383. {
  1384. m_traceLength = 0;
  1385. }
  1386. //m_trace.fraction = m_traceLength * m_ray->m_ooBaseLength;
  1387. //m_trace.endpos = m_ray->m_start*(1.f-m_trace.fraction) + m_ray->m_end*m_trace.fraction;
  1388. m_trace.contents = CONTENTS_SOLID;
  1389. }
  1390. else
  1391. {
  1392. // UNDONE: This case happens when you start solid as well as when a false
  1393. // intersection is detected at the very end of the trace
  1394. m_trace.startsolid = true;
  1395. m_trace.allsolid = true;
  1396. m_traceLength = 0;
  1397. }
  1398. }
  1399. else
  1400. {
  1401. m_trace.startsolid = true;
  1402. m_trace.allsolid = true;
  1403. m_traceLength = 0;
  1404. }
  1405. return true;
  1406. }
  1407. dir = -m_pointClosestToIntersection;
  1408. VectorNormalize_FastLowPrecision( dir );
  1409. }
  1410. // BUGBUG: The solution never converged - something is probably wrong!
  1411. AssertMsg( false, "Solution never converged.");
  1412. return false;
  1413. }
  1414. // NEW SWEPT GJK SOLVER 2/16/2006
  1415. // convenience routines - just makes the code a little simpler.
  1416. FORCEINLINE bool simplex_t::TriangleSimplex( const simplexvert_t &newPoint, int outIndex, const Vector &faceNormal, Vector *pOut )
  1417. {
  1418. vertCount = 3;
  1419. verts[outIndex] = newPoint;
  1420. *pOut = -faceNormal;
  1421. return false;
  1422. }
  1423. FORCEINLINE bool simplex_t::EdgeSimplex( const simplexvert_t &newPoint, int outIndex, const Vector &edge, Vector *pOut )
  1424. {
  1425. vertCount = 2;
  1426. verts[outIndex] = newPoint;
  1427. Vector cross;
  1428. CrossProduct( edge, newPoint.position, cross );
  1429. CrossProduct( cross, edge, *pOut );
  1430. return false;
  1431. }
  1432. FORCEINLINE bool simplex_t::PointSimplex( const simplexvert_t &newPoint, Vector *pOut )
  1433. {
  1434. vertCount = 1;
  1435. verts[0] = newPoint;
  1436. *pOut = newPoint.position;
  1437. return false;
  1438. }
  1439. // In general the voronoi region routines have comments referring to the verts
  1440. // All of the code assumes that vert A is the new vert being added to the set
  1441. // verts B, C, D are the previous set. If BCD is a triangle it is assumed to be
  1442. // counter-clockwise winding order. This must be maintained by the code!
  1443. // parametric value for closes point on a line segment (p0->p1) to the origin.
  1444. bool simplex_t::SolveVoronoiRegion2( const simplexvert_t &newPoint, Vector *pOut )
  1445. {
  1446. // solve the line segment AB (where A is the new point)
  1447. Vector AB = verts[0].position - newPoint.position;
  1448. float d = DotProduct(AB, newPoint.position);
  1449. if ( d < 0 )
  1450. {
  1451. return EdgeSimplex(newPoint, 1, AB, pOut);
  1452. }
  1453. else
  1454. {
  1455. return PointSimplex(newPoint, pOut);
  1456. }
  1457. }
  1458. // UNDONE: Collapse these routines into a single general routine?
  1459. bool simplex_t::SolveVoronoiRegion3( const simplexvert_t &newPoint, Vector *pOut )
  1460. {
  1461. // solve the triangle ABC (where A is the new point)
  1462. Vector AB = verts[0].position - newPoint.position;
  1463. Vector AC = verts[1].position - newPoint.position;
  1464. Vector ABC;
  1465. CrossProduct(AB, AC, ABC);
  1466. Vector ABCxAC;
  1467. CrossProduct(ABC, AC, ABCxAC);
  1468. float d = DotProduct(ABCxAC, newPoint.position);
  1469. // edge AC or edgeAB / A?
  1470. if ( d < 0 )
  1471. {
  1472. d = DotProduct(AC, newPoint.position);
  1473. if ( d < 0 )
  1474. {
  1475. // edge AC
  1476. return EdgeSimplex(newPoint, 0, AC, pOut);
  1477. }
  1478. }
  1479. else
  1480. {
  1481. // face or A / edge AB?
  1482. Vector ABxABC;
  1483. CrossProduct(AB, ABC, ABxABC);
  1484. d = DotProduct(ABxABC, newPoint.position);
  1485. if ( d > 0 )
  1486. {
  1487. // closest to face
  1488. vertCount = 3;
  1489. d = DotProduct(ABC, newPoint.position);
  1490. // in front of face, return opposite direction
  1491. if ( d < 0 )
  1492. {
  1493. verts[2] = newPoint;
  1494. *pOut = -ABC;
  1495. return false;
  1496. }
  1497. verts[2] = verts[1]; // swap to keep CCW
  1498. verts[1] = newPoint;
  1499. *pOut = ABC;
  1500. return false;
  1501. }
  1502. }
  1503. // edge AB or A
  1504. d = DotProduct(AB, newPoint.position);
  1505. if ( d < 0 )
  1506. {
  1507. return EdgeSimplex(newPoint, 1, AB, pOut);
  1508. }
  1509. return PointSimplex(newPoint, pOut);
  1510. }
  1511. bool simplex_t::SolveVoronoiRegion4( const simplexvert_t &newPoint, Vector *pOut )
  1512. {
  1513. // solve the tetrahedron ABCD (where A is the new point)
  1514. // compute edge vectors
  1515. Vector AB = verts[0].position - newPoint.position;
  1516. Vector AC = verts[1].position - newPoint.position;
  1517. Vector AD = verts[2].position - newPoint.position;
  1518. // compute face normals
  1519. Vector ABC, ACD, ADB;
  1520. CrossProduct( AB, AC, ABC );
  1521. CrossProduct( AC, AD, ACD );
  1522. CrossProduct( AD, AB, ADB );
  1523. // edge plane normals
  1524. Vector ABCxAC, ABxABC;
  1525. CrossProduct( ABC, AC, ABCxAC );
  1526. CrossProduct( AB, ABC, ABxABC );
  1527. Vector ACDxAD, ACxACD;
  1528. CrossProduct( ACD, AD, ACDxAD );
  1529. CrossProduct( AC, ACD, ACxACD );
  1530. Vector ADBxAB, ADxADB;
  1531. CrossProduct( ADB, AB, ADBxAB );
  1532. CrossProduct( AD, ADB, ADxADB );
  1533. int faceFlags = 0;
  1534. float d;
  1535. d = DotProduct(ABC,newPoint.position);
  1536. if ( d < 0 )
  1537. {
  1538. faceFlags |= 0x1;
  1539. }
  1540. d = DotProduct(ACD,newPoint.position);
  1541. if ( d < 0 )
  1542. {
  1543. faceFlags |= 0x2;
  1544. }
  1545. d = DotProduct(ADB,newPoint.position);
  1546. if ( d < 0 )
  1547. {
  1548. faceFlags |= 0x4;
  1549. }
  1550. switch( faceFlags )
  1551. {
  1552. case 0:
  1553. // inside all 3 faces, we're done
  1554. verts[3] = newPoint;
  1555. vertCount = 4;
  1556. return true;
  1557. case 1:
  1558. // ABC only, solve as a triangle
  1559. return SolveVoronoiRegion3(newPoint, pOut);
  1560. case 2:
  1561. // ACD only, solve as a triangle
  1562. verts[0] = verts[2]; // collapse BCD to DC
  1563. return SolveVoronoiRegion3(newPoint, pOut);
  1564. case 4:
  1565. // ADB only, solve as a triangle
  1566. verts[1] = verts[2]; // collapse BCD to BD
  1567. return SolveVoronoiRegion3(newPoint, pOut);
  1568. case 3:
  1569. {
  1570. // in front of ABC & ACD
  1571. d = DotProduct(ABCxAC, newPoint.position);
  1572. if ( d < 0 )
  1573. {
  1574. d = DotProduct(ACxACD, newPoint.position);
  1575. if ( d < 0 )
  1576. {
  1577. d = DotProduct(AC,newPoint.position);
  1578. if ( d < 0 )
  1579. {
  1580. // edge AC
  1581. return EdgeSimplex( newPoint, 0, AC, pOut);
  1582. }
  1583. // point A
  1584. return PointSimplex(newPoint, pOut);
  1585. }
  1586. else
  1587. {
  1588. d = DotProduct(ACDxAD, newPoint.position);
  1589. if ( d < 0 )
  1590. {
  1591. // edge AD
  1592. verts[0] = verts[2]; // collapse BCD to D
  1593. return EdgeSimplex(newPoint, 1, AD, pOut);
  1594. }
  1595. // face ACD
  1596. return TriangleSimplex(newPoint,0,ACD, pOut);
  1597. }
  1598. }
  1599. else
  1600. {
  1601. d = DotProduct(ABxABC, newPoint.position);
  1602. if ( d < 0 )
  1603. {
  1604. d = DotProduct(AB, newPoint.position);
  1605. if ( d < 0 )
  1606. {
  1607. // edge AB
  1608. return EdgeSimplex(newPoint, 1, AB, pOut);
  1609. }
  1610. return PointSimplex(newPoint, pOut);
  1611. }
  1612. return TriangleSimplex(newPoint,2,ABC,pOut);
  1613. }
  1614. }
  1615. break;
  1616. case 5:
  1617. {
  1618. // in front of ADB & ABC
  1619. d = DotProduct(ADBxAB, newPoint.position);
  1620. if ( d < 0 )
  1621. {
  1622. d = DotProduct(ABxABC, newPoint.position);
  1623. if ( d < 0 )
  1624. {
  1625. d = DotProduct(AB,newPoint.position);
  1626. if ( d < 0 )
  1627. {
  1628. // edge AB
  1629. return EdgeSimplex( newPoint, 1, AB , pOut);
  1630. }
  1631. // point A
  1632. return PointSimplex(newPoint, pOut);
  1633. }
  1634. else
  1635. {
  1636. d = DotProduct(ABCxAC, newPoint.position);
  1637. if ( d < 0 )
  1638. {
  1639. // edge AC
  1640. return EdgeSimplex(newPoint, 0, AC, pOut);
  1641. }
  1642. // face ABC
  1643. return TriangleSimplex(newPoint,2,ABC,pOut);
  1644. }
  1645. }
  1646. else
  1647. {
  1648. d = DotProduct(ADxADB, newPoint.position);
  1649. if ( d < 0 )
  1650. {
  1651. d = DotProduct(AD, newPoint.position);
  1652. if ( d < 0 )
  1653. {
  1654. // edge AD
  1655. verts[0] = verts[2]; // collapse BCD to D
  1656. return EdgeSimplex(newPoint, 1, AD, pOut);
  1657. }
  1658. return PointSimplex(newPoint, pOut);
  1659. }
  1660. return TriangleSimplex(newPoint,1,ADB,pOut);
  1661. }
  1662. }
  1663. break;
  1664. case 6:
  1665. {
  1666. // in front of ACD & ADB
  1667. d = DotProduct(ACDxAD, newPoint.position);
  1668. if ( d < 0 )
  1669. {
  1670. d = DotProduct(ADxADB, newPoint.position);
  1671. if ( d < 0 )
  1672. {
  1673. d = DotProduct(AD,newPoint.position);
  1674. if ( d < 0 )
  1675. {
  1676. // edge AD
  1677. verts[0] = verts[2]; // collapse BCD to D
  1678. return EdgeSimplex(newPoint, 1, AD, pOut);
  1679. }
  1680. // point A
  1681. return PointSimplex(newPoint, pOut);
  1682. }
  1683. else
  1684. {
  1685. d = DotProduct(ADBxAB, newPoint.position);
  1686. if ( d < 0 )
  1687. {
  1688. // edge AB
  1689. return EdgeSimplex(newPoint, 1, AB, pOut);
  1690. }
  1691. // face ADB
  1692. return TriangleSimplex(newPoint,1,ADB, pOut);
  1693. }
  1694. }
  1695. else
  1696. {
  1697. d = DotProduct(ACxACD, newPoint.position);
  1698. if ( d < 0 )
  1699. {
  1700. d = DotProduct(AC, newPoint.position);
  1701. if ( d < 0 )
  1702. {
  1703. // edge AC
  1704. return EdgeSimplex(newPoint, 0, AC, pOut);
  1705. }
  1706. return PointSimplex(newPoint, pOut);
  1707. }
  1708. return TriangleSimplex(newPoint,0,ACD, pOut);
  1709. }
  1710. }
  1711. break;
  1712. case 7:
  1713. {
  1714. d = DotProduct(AB, newPoint.position);
  1715. if ( d < 0 )
  1716. {
  1717. return EdgeSimplex(newPoint, 1, AB, pOut);
  1718. }
  1719. else
  1720. {
  1721. d = DotProduct(AC, newPoint.position);
  1722. if ( d < 0 )
  1723. {
  1724. return EdgeSimplex(newPoint, 0, AC, pOut);
  1725. }
  1726. else
  1727. {
  1728. d = DotProduct(AD, newPoint.position);
  1729. if ( d < 0 )
  1730. {
  1731. verts[0] = verts[2]; // collapse BCD to D
  1732. return EdgeSimplex(newPoint, 1, AD, pOut);
  1733. }
  1734. return PointSimplex(newPoint, pOut);
  1735. }
  1736. }
  1737. }
  1738. }
  1739. verts[3] = newPoint;
  1740. vertCount = 4;
  1741. return true;
  1742. }
  1743. bool simplex_t::SolveGJKSet( const simplexvert_t &w, Vector *pOut )
  1744. {
  1745. VPROF("TraceSolver::simplex::SolveGJKSet");
  1746. #if 0
  1747. for ( int v = 0; v < vertCount; v++ )
  1748. {
  1749. for ( int v2 = v+1; v2 < vertCount; v2++ )
  1750. {
  1751. if ( (verts[v].obstacleIndex == verts[v2].obstacleIndex) &&
  1752. (verts[v].sweepIndex == verts[v2].sweepIndex) &&
  1753. (verts[v].testIndex == verts[v2].testIndex) )
  1754. {
  1755. // same vert in the list twice! degenerate
  1756. Assert(0);
  1757. }
  1758. }
  1759. }
  1760. #endif
  1761. switch( vertCount )
  1762. {
  1763. case 0:
  1764. vertCount = 1;
  1765. verts[0] = w;
  1766. *pOut = w.position;
  1767. return false;
  1768. case 1:
  1769. return SolveVoronoiRegion2( w, pOut );
  1770. case 2:
  1771. return SolveVoronoiRegion3( w, pOut );
  1772. case 3:
  1773. return SolveVoronoiRegion4( w, pOut );
  1774. }
  1775. return true;
  1776. }
  1777. void CalculateSeparatingPlane( trace_t *ptr, ITraceObject *sweepObject, CTraceRay *ray, ITraceObject *obstacle, simplex_t &simplex )
  1778. {
  1779. int testCount = 1, obstacleCount = 1;
  1780. unsigned int testIndex[4], obstacleIndex[4];
  1781. testIndex[0] = simplex.verts[0].testIndex;
  1782. obstacleIndex[0] = simplex.verts[0].obstacleIndex;
  1783. Assert( simplex.vertCount <= 4 );
  1784. int i, j;
  1785. for ( i = 1; i < simplex.vertCount; i++ )
  1786. {
  1787. for ( j = 0; j < obstacleCount; j++ )
  1788. {
  1789. if ( obstacleIndex[j] == simplex.verts[i].obstacleIndex )
  1790. break;
  1791. }
  1792. if ( j == obstacleCount )
  1793. {
  1794. obstacleIndex[obstacleCount++] = simplex.verts[i].obstacleIndex;
  1795. }
  1796. for ( j = 0; j < testCount; j++ )
  1797. {
  1798. if ( testIndex[j] == simplex.verts[i].testIndex )
  1799. break;
  1800. }
  1801. if ( j == testCount )
  1802. {
  1803. testIndex[testCount++] = simplex.verts[i].testIndex;
  1804. }
  1805. }
  1806. if ( simplex.vertCount < 3 )
  1807. {
  1808. if ( simplex.vertCount == 2 && testCount == 2 )
  1809. {
  1810. // edge / point
  1811. Vector t0 = sweepObject->GetVertByIndex( testIndex[0] );
  1812. Vector t1 = sweepObject->GetVertByIndex( testIndex[1] );
  1813. Vector edge = t1-t0;
  1814. Vector tangent = CrossProduct( edge, ray->m_delta );
  1815. ptr->plane.normal = CrossProduct( edge, tangent );
  1816. VectorNormalize( ptr->plane.normal );
  1817. ptr->plane.dist = DotProduct( t0 + ptr->endpos, ptr->plane.normal );
  1818. return;
  1819. }
  1820. }
  1821. if ( testCount == 3 )
  1822. {
  1823. // face / xxx
  1824. Vector t0 = sweepObject->GetVertByIndex( testIndex[0] );
  1825. Vector t1 = sweepObject->GetVertByIndex( testIndex[1] );
  1826. Vector t2 = sweepObject->GetVertByIndex( testIndex[2] );
  1827. ptr->plane.normal = CrossProduct( t1-t0, t2-t0 );
  1828. VectorNormalize( ptr->plane.normal );
  1829. if ( DotProduct( ptr->plane.normal, ray->m_delta ) > 0 )
  1830. {
  1831. ptr->plane.normal = -ptr->plane.normal;
  1832. }
  1833. ptr->plane.dist = DotProduct( t0 + ptr->endpos, ptr->plane.normal );
  1834. }
  1835. else if ( testCount == 2 && obstacleCount == 2 )
  1836. {
  1837. // edge / edge
  1838. Vector t0 = sweepObject->GetVertByIndex( testIndex[0] );
  1839. Vector t1 = sweepObject->GetVertByIndex( testIndex[1] );
  1840. Vector t2 = obstacle->GetVertByIndex( obstacleIndex[0] );
  1841. Vector t3 = obstacle->GetVertByIndex( obstacleIndex[1] );
  1842. ptr->plane.normal = CrossProduct( t1-t0, t3-t2 );
  1843. VectorNormalize( ptr->plane.normal );
  1844. if ( DotProduct( ptr->plane.normal, ray->m_delta ) > 0 )
  1845. {
  1846. ptr->plane.normal = -ptr->plane.normal;
  1847. }
  1848. ptr->plane.dist = DotProduct( t0 + ptr->endpos, ptr->plane.normal );
  1849. }
  1850. else if ( obstacleCount == 3 )
  1851. {
  1852. // xxx / face
  1853. Vector t0 = obstacle->GetVertByIndex( obstacleIndex[0] );
  1854. Vector t1 = obstacle->GetVertByIndex( obstacleIndex[1] );
  1855. Vector t2 = obstacle->GetVertByIndex( obstacleIndex[2] );
  1856. ptr->plane.normal = CrossProduct( t1-t0, t2-t0 );
  1857. VectorNormalize( ptr->plane.normal );
  1858. if ( DotProduct( ptr->plane.normal, ray->m_delta ) > 0 )
  1859. {
  1860. ptr->plane.normal = -ptr->plane.normal;
  1861. }
  1862. ptr->plane.dist = DotProduct( t0, ptr->plane.normal );
  1863. }
  1864. else
  1865. {
  1866. ptr->plane.normal = -ray->m_dir;
  1867. if ( simplex.vertCount )
  1868. {
  1869. ptr->plane.dist = DotProduct( ptr->plane.normal, obstacle->GetVertByIndex( simplex.verts[0].obstacleIndex ) );
  1870. }
  1871. else
  1872. ptr->plane.dist = 0.f;
  1873. }
  1874. }
  1875. // clip a direction vector to a plane (ray begins at the origin)
  1876. inline float Clip( const Vector &dir, const Vector &pos, const Vector &normal )
  1877. {
  1878. float dist = DotProduct(pos, normal);
  1879. float cosTheta = DotProduct(dir,normal);
  1880. if ( cosTheta > 0 )
  1881. return dist / cosTheta;
  1882. // parallel or not facing the plane
  1883. return 1e24f;
  1884. }
  1885. // This is the first iteration of solving time of intersection.
  1886. // It needs to test all 4 faces of the tetrahedron to find the one the ray leaves through
  1887. // this is done by finding the closest plane by clipping the ray to each plane
  1888. Vector simplex_t::ClipRayToTetrahedronBase( const Vector &dir )
  1889. {
  1890. Vector AB = verts[0].position - verts[3].position;
  1891. Vector AC = verts[1].position - verts[3].position;
  1892. Vector AD = verts[2].position - verts[3].position;
  1893. Vector BC = verts[1].position - verts[0].position;
  1894. Vector BD = verts[2].position - verts[0].position;
  1895. // compute face normals
  1896. Vector ABC, ACD, ADB, BCD;
  1897. CrossProduct( AB, AC, ABC );
  1898. CrossProduct( AC, AD, ACD );
  1899. CrossProduct( AD, AB, ADB );
  1900. CrossProduct( BD, BC, BCD ); // flipped to point out of the tetrahedron
  1901. // NOTE: These cancel out in the clipping equation
  1902. //VectorNormalize(ABC);
  1903. //VectorNormalize(ACD);
  1904. //VectorNormalize(ADB);
  1905. //VectorNormalize(BCD);
  1906. // Assert valid tetrahedron/winding order
  1907. #if CHECK_TOI_CALCS
  1908. Assert(DotProduct(verts[2].position, ABC) < DotProduct(verts[3].position, ABC ));
  1909. Assert(DotProduct(verts[0].position, ACD) < DotProduct(verts[3].position, ACD ));
  1910. Assert(DotProduct(verts[1].position, ADB) < DotProduct(verts[3].position, ADB ));
  1911. Assert(DotProduct(verts[3].position, BCD) < DotProduct(verts[0].position, BCD ));
  1912. #endif
  1913. float dists[4];
  1914. dists[0] = Clip( dir, verts[3].position, ABC );
  1915. dists[1] = Clip( dir, verts[3].position, ACD );
  1916. dists[2] = Clip( dir, verts[3].position, ADB );
  1917. dists[3] = Clip( dir, verts[0].position, BCD );
  1918. float dmin = dists[3];
  1919. int best = 3;
  1920. for ( int i = 0; i < 3; i++ )
  1921. {
  1922. if ( dists[i] < dmin )
  1923. {
  1924. best = i;
  1925. dmin = dists[i];
  1926. }
  1927. }
  1928. vertCount = 3;
  1929. // push back down to a triangle
  1930. // Note that we need to preserve winding so that the vector order assumptions above are still valid!
  1931. switch( best )
  1932. {
  1933. case 0:
  1934. verts[2] = verts[3];
  1935. return ABC;
  1936. case 1:
  1937. verts[0] = verts[3];
  1938. return ACD;
  1939. case 2:
  1940. verts[1] = verts[3];
  1941. return ADB;
  1942. case 3:
  1943. // swap 1 & 2
  1944. verts[3] = verts[1];
  1945. verts[1] = verts[2];
  1946. verts[2] = verts[3];
  1947. return BCD;
  1948. }
  1949. Assert(0); // failed!
  1950. return vec3_origin;
  1951. }
  1952. // for subsequent iterations you don't need to test one of the faces (face you previously left through)
  1953. // so only test the three faces involving the new point A
  1954. Vector simplex_t::ClipRayToTetrahedron( const Vector &dir )
  1955. {
  1956. Vector AB = verts[0].position - verts[3].position;
  1957. Vector AC = verts[1].position - verts[3].position;
  1958. Vector AD = verts[2].position - verts[3].position;
  1959. // compute face normals
  1960. Vector ABC, ACD, ADB;
  1961. CrossProduct( AB, AC, ABC );
  1962. CrossProduct( AC, AD, ACD );
  1963. CrossProduct( AD, AB, ADB );
  1964. // NOTE: These cancel out in the clipping equation
  1965. //VectorNormalize(ABC);
  1966. //VectorNormalize(ACD);
  1967. //VectorNormalize(ADB);
  1968. // Assert valid tetrahedron/winding order
  1969. #if CHECK_TOI_CALCS
  1970. Assert(DotProduct(verts[2].position, ABC) < DotProduct(verts[3].position, ABC ));
  1971. Assert(DotProduct(verts[0].position, ACD) < DotProduct(verts[3].position, ACD ));
  1972. Assert(DotProduct(verts[1].position, ADB) < DotProduct(verts[3].position, ADB ));
  1973. #endif
  1974. float dists[3];
  1975. dists[0] = Clip( dir, verts[3].position, ABC );
  1976. dists[1] = Clip( dir, verts[3].position, ACD );
  1977. dists[2] = Clip( dir, verts[3].position, ADB );
  1978. float dmin = dists[2];
  1979. int best = 2;
  1980. for ( int i = 0; i < 2; i++ )
  1981. {
  1982. if ( dists[i] < dmin )
  1983. {
  1984. best = i;
  1985. dmin = dists[i];
  1986. }
  1987. }
  1988. vertCount = 3;
  1989. // push back down to a triangle
  1990. // Note that we need to preserve winding so that the vector order assumptions above are still valid!
  1991. switch( best )
  1992. {
  1993. case 0:
  1994. verts[2] = verts[3];
  1995. return ABC;
  1996. case 1:
  1997. verts[0] = verts[3];
  1998. return ACD;
  1999. case 2:
  2000. verts[1] = verts[3];
  2001. return ADB;
  2002. }
  2003. return vec3_origin;
  2004. }
  2005. float simplex_t::ClipRayToTriangle( const Vector &dir, float epsilon )
  2006. {
  2007. Vector AB = verts[0].position - verts[2].position;
  2008. Vector AC = verts[1].position - verts[2].position;
  2009. Vector BC = verts[1].position - verts[0].position;
  2010. // compute face normal
  2011. Vector ABC;
  2012. CrossProduct( AB, AC, ABC ); // this points toward the origin
  2013. VectorNormalize(ABC);
  2014. Vector edgeAB, edgeAC, edgeBC;
  2015. // these should point out of the triangle
  2016. CrossProduct( AB, ABC, edgeAB );
  2017. CrossProduct( ABC, AC, edgeAC );
  2018. CrossProduct( BC, ABC, edgeBC );
  2019. // NOTE: These cancel out in the clipping equation
  2020. VectorNormalize(edgeAB);
  2021. VectorNormalize(edgeAC);
  2022. VectorNormalize(edgeBC);
  2023. #if CHECK_TOI_CALCS
  2024. Assert(DotProduct(verts[2].position, ABC) < 0); // points toward
  2025. // Assert valid triangle/winding order (all normals point away from the origin)
  2026. Assert(DotProduct(verts[2].position, edgeAB) > 0);
  2027. Assert(DotProduct(verts[2].position, edgeAC) > 0);
  2028. Assert(DotProduct(verts[0].position, edgeBC) > 0);
  2029. #endif
  2030. float dists[3];
  2031. dists[0] = Clip( dir, verts[0].position, edgeAB );
  2032. dists[1] = Clip( dir, verts[1].position, edgeAC );
  2033. dists[2] = Clip( dir, verts[1].position, edgeBC );
  2034. Vector *normals[3] = {&edgeAB, &edgeAC, &edgeBC};
  2035. float dmin = dists[0];
  2036. int best = 0;
  2037. if ( dists[1] < dmin )
  2038. {
  2039. dmin = dists[1];
  2040. best = 1;
  2041. }
  2042. if ( dists[2] < dmin )
  2043. {
  2044. best = 2;
  2045. dmin = dists[2];
  2046. }
  2047. float dot = DotProduct( dir, *normals[best] );
  2048. if ( dot <= 0 )
  2049. return 1e24f;
  2050. dmin += epsilon/dot;
  2051. return dmin;
  2052. }
  2053. // Solve for time of intersection along the sweep
  2054. // Do this by iteratively clipping the ray to the tetrahedron containing the origin
  2055. // when a triangle is found intersecting the ray, reduce the simplex to that triangle
  2056. // and then re-expand it to a tetrahedron using the support point normal to the triangle (away from the origin)
  2057. // iterate until no new points can be found. That's the surface of the sum.
  2058. float CTraceSolver::SolveMeshIntersection( simplex_t &simplex )
  2059. {
  2060. Vector tmp;
  2061. Assert( simplex.vertCount == 4 );
  2062. if ( simplex.vertCount < 4 )
  2063. return 0.0f;
  2064. Vector v = simplex.ClipRayToTetrahedronBase( m_ray->m_dir );
  2065. simplexvert_t vert;
  2066. // safe loop, max 100 iterations
  2067. for ( int i = 0; i < 100; i++ )
  2068. {
  2069. VectorNormalize(v);
  2070. vert.testIndex = m_sweepObject->SupportMap( v, &vert.position );
  2071. vert.sweepIndex = m_ray->SupportMap( v, &tmp );
  2072. VectorAdd( vert.position, tmp, vert.position );
  2073. vert.obstacleIndex = m_obstacle->SupportMap( -v, &tmp );
  2074. VectorSubtract( vert.position, tmp, vert.position );
  2075. // map the new separating axis (NOTE: This test is inverted from the GJK - we are trying to get out, not in)
  2076. // found a separating axis, we've moved the sweep back enough
  2077. float dist = DotProduct( v, simplex.verts[0].position ) + TEST_EPSILON;
  2078. if ( DotProduct( v, vert.position ) <= dist )
  2079. {
  2080. Vector BC = simplex.verts[1].position - simplex.verts[0].position;
  2081. Vector BD = simplex.verts[2].position - simplex.verts[0].position;
  2082. // compute face normals
  2083. Vector BCD;
  2084. CrossProduct( BC, BD, BCD );
  2085. // NOTE: This cancels out inside Clip()
  2086. //VectorNormalize( BCD );
  2087. // clip ray to triangle
  2088. return Clip( m_ray->m_dir, simplex.verts[0].position, BCD );
  2089. }
  2090. // add the new vert
  2091. simplex.verts[simplex.vertCount] = vert;
  2092. simplex.vertCount++;
  2093. v = simplex.ClipRayToTetrahedron( m_ray->m_dir );
  2094. }
  2095. Assert(0);
  2096. return 0.0f;
  2097. }
  2098. // similar to SolveMeshIntersection, but solves projected into the 2D triangle simplex remaining
  2099. // this is used for the near miss case
  2100. float CTraceSolver::SolveMeshIntersection2D( simplex_t &simplex )
  2101. {
  2102. AssertMsg( simplex.vertCount == 3, "simplex.vertCount != 3: %d", simplex.vertCount );
  2103. if ( simplex.vertCount != 3 )
  2104. return 0.0f;
  2105. // note: This should really do this iteratively in case the triangle is coplanar with another triangle that
  2106. // is between this one and the edge of the sum in this plane
  2107. float dist = simplex.ClipRayToTriangle( m_ray->m_dir, m_epsilon );
  2108. return dist;
  2109. }
  2110. static const Vector g_xpos(1,0,0), g_xneg(-1,0,0);
  2111. static const Vector g_ypos(0,1,0), g_yneg(0,-1,0);
  2112. static const Vector g_zpos(0,0,1), g_zneg(0,0,-1);
  2113. void TraceGetAABB_r( Vector *pMins, Vector *pMaxs, const IVP_Compact_Ledgetree_Node *node, CTraceIVP &ivp )
  2114. {
  2115. if ( node->is_terminal() == IVP_TRUE )
  2116. {
  2117. Vector tmp;
  2118. ivp.SetLedge( node->get_compact_ledge() );
  2119. ivp.SupportMap( g_xneg, &tmp );
  2120. AddPointToBounds( tmp, *pMins, *pMaxs );
  2121. ivp.SupportMap( g_yneg, &tmp );
  2122. AddPointToBounds( tmp, *pMins, *pMaxs );
  2123. ivp.SupportMap( g_zneg, &tmp );
  2124. AddPointToBounds( tmp, *pMins, *pMaxs );
  2125. ivp.SupportMap( g_xpos, &tmp );
  2126. AddPointToBounds( tmp, *pMins, *pMaxs );
  2127. ivp.SupportMap( g_ypos, &tmp );
  2128. AddPointToBounds( tmp, *pMins, *pMaxs );
  2129. ivp.SupportMap( g_zpos, &tmp );
  2130. AddPointToBounds( tmp, *pMins, *pMaxs );
  2131. return;
  2132. }
  2133. TraceGetAABB_r( pMins, pMaxs, node->left_son(), ivp );
  2134. TraceGetAABB_r( pMins, pMaxs, node->right_son(), ivp );
  2135. }
  2136. void CPhysicsTrace::GetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles )
  2137. {
  2138. CTraceIVP ivp( pCollide, collideOrigin, collideAngles );
  2139. if ( ivp.SetSingleConvex() )
  2140. {
  2141. Vector tmp;
  2142. ivp.SupportMap( g_xneg, &tmp );
  2143. pMins->x = tmp.x;
  2144. ivp.SupportMap( g_yneg, &tmp );
  2145. pMins->y = tmp.y;
  2146. ivp.SupportMap( g_zneg, &tmp );
  2147. pMins->z = tmp.z;
  2148. ivp.SupportMap( g_xpos, &tmp );
  2149. pMaxs->x = tmp.x;
  2150. ivp.SupportMap( g_ypos, &tmp );
  2151. pMaxs->y = tmp.y;
  2152. ivp.SupportMap( g_zpos, &tmp );
  2153. pMaxs->z = tmp.z;
  2154. }
  2155. else
  2156. {
  2157. const IVP_Compact_Ledgetree_Node *lt_node_root;
  2158. lt_node_root = pCollide->GetCompactSurface()->get_compact_ledge_tree_root();
  2159. ClearBounds( *pMins, *pMaxs );
  2160. TraceGetAABB_r( pMins, pMaxs, lt_node_root, ivp );
  2161. }
  2162. // JAY: Disable this here, do it in the engine instead. That way the tools get
  2163. // accurate bboxes
  2164. #if 0
  2165. const float radius = g_PhysicsUnits.collisionSweepEpsilon;
  2166. mins -= Vector(radius,radius,radius);
  2167. maxs += Vector(radius,radius,radius);
  2168. #endif
  2169. }
  2170. void TraceGetExtent_r( const IVP_Compact_Ledgetree_Node *node, CTraceIVP &ivp, const Vector &dir, float &dot, Vector &point )
  2171. {
  2172. if ( node->is_terminal() == IVP_TRUE )
  2173. {
  2174. ivp.SetLedge( node->get_compact_ledge() );
  2175. Vector tmp;
  2176. ivp.SupportMap( dir, &tmp );
  2177. float newDot = DotProduct( tmp, dir );
  2178. if ( newDot > dot )
  2179. {
  2180. dot = newDot;
  2181. point = tmp;
  2182. }
  2183. return;
  2184. }
  2185. TraceGetExtent_r( node->left_son(), ivp, dir, dot, point );
  2186. TraceGetExtent_r( node->right_son(), ivp, dir, dot, point );
  2187. }
  2188. Vector CPhysicsTrace::GetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction )
  2189. {
  2190. CTraceIVP ivp( pCollide, collideOrigin, collideAngles );
  2191. if ( ivp.SetSingleConvex() )
  2192. {
  2193. Vector tmp;
  2194. ivp.SupportMap( direction, &tmp );
  2195. return tmp;
  2196. }
  2197. else
  2198. {
  2199. const IVP_Compact_Ledgetree_Node *lt_node_root;
  2200. lt_node_root = pCollide->GetCompactSurface()->get_compact_ledge_tree_root();
  2201. Vector out = vec3_origin;
  2202. float tmp = -1e6f;
  2203. TraceGetExtent_r( lt_node_root, ivp, direction, tmp, out );
  2204. return out;
  2205. }
  2206. }
  2207. bool CPhysicsTrace::IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone )
  2208. {
  2209. trace_t tr;
  2210. CM_ClearTrace( &tr );
  2211. bool bPoint = (boxAbsMins == boxAbsMaxs) ? true : false;
  2212. CTraceAABB box( boxAbsMins - cone.origin, boxAbsMaxs - cone.origin, bPoint );
  2213. CTraceCone traceCone( cone, -cone.origin );
  2214. // offset the space of this sweep so that the surface is at the origin of the solution space
  2215. CTraceRay ray( vec3_origin, vec3_origin );
  2216. CTraceSolver solver( &tr, &box, &ray, &traceCone, boxAbsMaxs );
  2217. solver.DoSweep();
  2218. return tr.startsolid;
  2219. }
  2220. CPhysicsTrace::CPhysicsTrace()
  2221. {
  2222. }
  2223. CPhysicsTrace::~CPhysicsTrace()
  2224. {
  2225. }
  2226. CVisitHash::CVisitHash()
  2227. {
  2228. m_vertVisitID = 1;
  2229. memset( m_vertVisit, 0, sizeof(m_vertVisit) );
  2230. }