Counter Strike : Global Offensive Source Code
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.

500 lines
21 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Common collision utility methods
  4. //
  5. // $Header: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef COLLISIONUTILS_H
  9. #define COLLISIONUTILS_H
  10. #include "tier0/platform.h"
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. #include "mathlib/ssemath.h"
  15. //-----------------------------------------------------------------------------
  16. // forward declarations
  17. //-----------------------------------------------------------------------------
  18. struct Ray_t;
  19. class Vector;
  20. class Vector2D;
  21. class Vector4D;
  22. struct cplane_t;
  23. class QAngle;
  24. class CBaseTrace;
  25. struct matrix3x4_t;
  26. //-----------------------------------------------------------------------------
  27. //
  28. // IntersectRayWithTriangle
  29. //
  30. // Intersects a ray with a triangle, returns distance t along ray.
  31. // t will be less than zero if no intersection occurred
  32. // oneSided will cull collisions which approach the triangle from the back
  33. // side, assuming the vertices are specified in counter-clockwise order
  34. // The vertices need not be specified in that order if oneSided is not used
  35. //
  36. //-----------------------------------------------------------------------------
  37. float IntersectRayWithTriangle( const Ray_t& ray,
  38. const Vector& v1, const Vector& v2, const Vector& v3,
  39. bool oneSided );
  40. //-----------------------------------------------------------------------------
  41. //
  42. // ComputeIntersectionBarycentricCoordinates
  43. //
  44. // Figures out the barycentric coordinates (u,v) where a ray hits a
  45. // triangle. Note that this will ignore the ray extents, and it also ignores
  46. // the ray length. Note that the edge from v1->v2 represents u (v2: u = 1),
  47. // and the edge from v1->v3 represents v (v3: v = 1). It returns false
  48. // if the ray is parallel to the triangle (or when t is specified if t is less
  49. // than zero).
  50. //
  51. //-----------------------------------------------------------------------------
  52. bool ComputeIntersectionBarycentricCoordinates( const Ray_t& ray,
  53. const Vector& v1, const Vector& v2, const Vector& v3, float& u, float& v,
  54. float *t = 0 );
  55. //-----------------------------------------------------------------------------
  56. //
  57. // IntersectRayWithRay
  58. //
  59. // Returns whether or not there was an intersection. The "t" paramter is the
  60. // distance along ray0 and the "s" parameter is the distance along ray1. If
  61. // the two lines to not intersect the "t" and "s" represent the closest approach.
  62. // "t" and "s" will not change if the rays are parallel.
  63. //
  64. //-----------------------------------------------------------------------------
  65. bool IntersectRayWithRay( const Ray_t &ray0, const Ray_t &ray1, float &t, float &s );
  66. //-----------------------------------------------------------------------------
  67. //
  68. // IntersectRayWithSphere
  69. //
  70. // Returns whether or not there was an intersection. Returns the two intersection points.
  71. // NOTE: The point of closest approach can be found at the average t value.
  72. //
  73. //-----------------------------------------------------------------------------
  74. bool IntersectRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 );
  75. //-----------------------------------------------------------------------------
  76. //
  77. // IntersectInfiniteRayWithSphere
  78. //
  79. // Returns whether or not there was an intersection of a sphere against an infinitely
  80. // extending ray.
  81. // Returns the two intersection points
  82. //
  83. //-----------------------------------------------------------------------------
  84. bool IntersectInfiniteRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta,
  85. const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 );
  86. // returns true if the sphere and cone intersect
  87. // NOTE: cone sine/cosine are the half angle of the cone
  88. bool IsSphereIntersectingCone( const Vector &sphereCenter, float sphereRadius, const Vector &coneOrigin, const Vector &coneNormal, float coneSine, float coneCosine );
  89. //-----------------------------------------------------------------------------
  90. //
  91. // IntersectRayWithPlane
  92. //
  93. // Intersects a ray with a plane, returns distance t along ray.
  94. // t will be less than zero the intersection occurs in the opposite direction of the ray.
  95. //
  96. //-----------------------------------------------------------------------------
  97. float IntersectRayWithPlane( const Ray_t& ray, const cplane_t& plane );
  98. float IntersectRayWithPlane( const Vector& org, const Vector& dir, const cplane_t& plane );
  99. float IntersectRayWithPlane( const Vector& org, const Vector& dir, const Vector& normal, float dist );
  100. // This version intersects a ray with an axis-aligned plane
  101. float IntersectRayWithAAPlane( const Vector& vecStart, const Vector& vecEnd, int nAxis, float flSign, float flDist );
  102. //-----------------------------------------------------------------------------
  103. // IntersectRayWithBox
  104. //
  105. // Purpose: Computes the intersection of a ray with a box (AABB)
  106. // Output : Returns true if there is an intersection + trace information
  107. //-----------------------------------------------------------------------------
  108. bool IntersectRayWithBox( const Vector &rayStart, const Vector &rayDelta, const Vector &boxMins, const Vector &boxMaxs, float epsilon, CBaseTrace *pTrace, float *pFractionLeftSolid = NULL );
  109. bool IntersectRayWithBox( const Ray_t &ray, const Vector &boxMins, const Vector &boxMaxs, float epsilon, CBaseTrace *pTrace, float *pFractionLeftSolid = NULL );
  110. //-----------------------------------------------------------------------------
  111. // Intersects a ray against a box
  112. //-----------------------------------------------------------------------------
  113. struct BoxTraceInfo_t
  114. {
  115. float t1;
  116. float t2;
  117. int hitside;
  118. bool startsolid;
  119. };
  120. bool IntersectRayWithBox( const Vector &vecRayStart, const Vector &vecRayDelta,
  121. const Vector &boxMins, const Vector &boxMaxs, float flTolerance, BoxTraceInfo_t *pTrace );
  122. //-----------------------------------------------------------------------------
  123. // IntersectRayWithOBB
  124. //
  125. // Purpose: Computes the intersection of a ray with a oriented box (OBB)
  126. // Output : Returns true if there is an intersection + trace information
  127. //-----------------------------------------------------------------------------
  128. bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta,
  129. const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs,
  130. float flTolerance, CBaseTrace *pTrace );
  131. bool IntersectRayWithOBB( const Vector &vecRayOrigin, const Vector &vecRayDelta,
  132. const Vector &vecBoxOrigin, const QAngle &angBoxRotation,
  133. const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace );
  134. bool IntersectRayWithOBB( const Ray_t &ray, const Vector &vecBoxOrigin, const QAngle &angBoxRotation,
  135. const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace );
  136. bool IntersectRayWithOBB( const Ray_t &ray, const matrix3x4_t &matOBBToWorld,
  137. const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace );
  138. bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta,
  139. const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs,
  140. float flTolerance, BoxTraceInfo_t *pTrace );
  141. //-----------------------------------------------------------------------------
  142. //
  143. // IsSphereIntersectingSphere
  144. //
  145. // returns true if there's an intersection between sphere and sphere
  146. //
  147. //-----------------------------------------------------------------------------
  148. bool IsSphereIntersectingSphere( const Vector& center1, float radius1,
  149. const Vector& center2, float radius2 );
  150. //-----------------------------------------------------------------------------
  151. //
  152. // IsBoxIntersectingSphere
  153. //
  154. // returns true if there's an intersection between box and sphere
  155. //
  156. //-----------------------------------------------------------------------------
  157. bool IsBoxIntersectingSphere( const Vector& boxMin, const Vector& boxMax,
  158. const Vector& center, float radius );
  159. bool IsBoxIntersectingSphereExtents( const Vector& boxCenter, const Vector& boxHalfDiag,
  160. const Vector& center, float radius );
  161. //-----------------------------------------------------------------------------
  162. // Returns true if a box intersects with a sphere
  163. // NOTE: f4RadiusSq must have the radius sq in all components
  164. //-----------------------------------------------------------------------------
  165. FORCEINLINE bool IsBoxIntersectingSphere( const Vector& boxMin, const Vector& boxMax,
  166. const fltx4& f4Center, const fltx4& f4RadiusSq )
  167. {
  168. // See Graphics Gems, box-sphere intersection
  169. fltx4 f4Mins = LoadUnalignedSIMD( &boxMin.x );
  170. fltx4 f4Maxs = LoadUnalignedSIMD( &boxMax.x );
  171. fltx4 f4MinDelta = SubSIMD( f4Mins, f4Center );
  172. fltx4 f4MaxDelta = SubSIMD( f4Center, f4Maxs );
  173. f4MinDelta = MaxSIMD( f4MinDelta, Four_Zeros );
  174. f4MaxDelta = MaxSIMD( f4MaxDelta, Four_Zeros );
  175. fltx4 f4Delta = AddSIMD( f4MinDelta, f4MaxDelta );
  176. fltx4 f4DistSq = Dot3SIMD( f4Delta, f4Delta );
  177. return IsAllGreaterThan( f4RadiusSq, f4DistSq );
  178. }
  179. //-----------------------------------------------------------------------------
  180. // returns true if there's an intersection between ray and sphere
  181. //-----------------------------------------------------------------------------
  182. bool IsRayIntersectingSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta,
  183. const Vector &vecSphereCenter, float flRadius, float flTolerance = 0.0f );
  184. //-----------------------------------------------------------------------------
  185. //
  186. // IsCircleIntersectingRectangle
  187. //
  188. // returns true if there's an intersection between rectangle and circle
  189. //
  190. //-----------------------------------------------------------------------------
  191. bool IsCircleIntersectingRectangle( const Vector2D& boxMin, const Vector2D& boxMax,
  192. const Vector2D& center, float radius );
  193. //-----------------------------------------------------------------------------
  194. //
  195. // IsBoxIntersectingBox
  196. //
  197. // returns true if there's an intersection between two boxes
  198. //
  199. //-----------------------------------------------------------------------------
  200. bool IsBoxIntersectingBox( const Vector& boxMin1, const Vector& boxMax1,
  201. const Vector& boxMin2, const Vector& boxMax2 );
  202. bool IsBoxIntersectingBoxExtents( const Vector& boxCenter1, const Vector& boxHalfDiagonal1,
  203. const Vector& boxCenter2, const Vector& boxHalfDiagonal2 );
  204. #ifdef _X360
  205. // inline version:
  206. #include "mathlib/ssemath.h"
  207. inline bool IsBoxIntersectingBoxExtents( const fltx4 boxCenter1, const fltx4 boxHalfDiagonal1,
  208. const fltx4 boxCenter2, const fltx4 boxHalfDiagonal2 );
  209. #endif
  210. //-----------------------------------------------------------------------------
  211. //
  212. // IsOBBIntersectingOBB
  213. //
  214. // returns true if there's an intersection between two OBBs
  215. //
  216. //-----------------------------------------------------------------------------
  217. bool IsOBBIntersectingOBB( const Vector &vecOrigin1, const QAngle &vecAngles1, const Vector& boxMin1, const Vector& boxMax1,
  218. const Vector &vecOrigin2, const QAngle &vecAngles2, const Vector& boxMin2, const Vector& boxMax2, float flTolerance = 0.0f );
  219. //-----------------------------------------------------------------------------
  220. //
  221. // IsBoxIntersectingRay
  222. //
  223. // returns true if there's an intersection between box and ray
  224. //
  225. //-----------------------------------------------------------------------------
  226. bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax,
  227. const Vector& origin, const Vector& delta, float flTolerance = 0.0f );
  228. bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax,
  229. const Ray_t& ray, float flTolerance );
  230. bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax,
  231. const Vector& origin, const Vector& delta,
  232. const Vector& invDelta, float flTolerance = 0.0f );
  233. // On the PC, we can't pass fltx4's in registers like this. On the x360, it is
  234. // much better if we do.
  235. #if defined( _X360 ) || defined( _PS3 )
  236. bool FASTCALL IsBoxIntersectingRay( fltx4 boxMin, fltx4 boxMax,
  237. fltx4 origin, fltx4 delta, fltx4 invDelta, // ray parameters
  238. fltx4 vTolerance = LoadZeroSIMD() ///< eg from ReplicateX4(flTolerance)
  239. );
  240. #else
  241. bool FASTCALL IsBoxIntersectingRay( const fltx4 &boxMin, const fltx4 &boxMax,
  242. const fltx4 & origin, const fltx4 & delta, const fltx4 & invDelta, // ray parameters
  243. const fltx4 & vTolerance = Four_Zeros ///< eg from ReplicateX4(flTolerance)
  244. );
  245. #endif
  246. bool inline FASTCALL IsBoxIntersectingRay( const fltx4& boxMin, const fltx4& boxMax,
  247. const fltx4& origin, const fltx4& delta, float flTolerance = 0.0f )
  248. {
  249. return IsBoxIntersectingRay( boxMin, boxMax, origin, delta, ReciprocalSIMD(delta), ReplicateX4(flTolerance) );
  250. }
  251. #if defined( _X360 ) || defined( _PS3 )
  252. bool FASTCALL IsBoxIntersectingRay( fltx4 boxMin, fltx4 boxMax,
  253. const Ray_t& ray, fltx4 fl4Tolerance = LoadZeroSIMD() );
  254. #else
  255. bool FASTCALL IsBoxIntersectingRay( const fltx4& boxMin, const fltx4& boxMax,
  256. const Ray_t& ray, const fltx4 &fl4Tolerance = LoadZeroSIMD() );
  257. #endif
  258. FORCEINLINE bool IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, const Ray_t& ray )
  259. {
  260. return IsBoxIntersectingRay( LoadUnaligned3SIMD(boxMin.Base()), LoadUnaligned3SIMD(boxMax.Base()), ray, LoadZeroSIMD() );
  261. }
  262. //-----------------------------------------------------------------------------
  263. //
  264. // IsPointInBox
  265. //
  266. // returns true if the point is in the box
  267. //
  268. //-----------------------------------------------------------------------------
  269. bool IsPointInBox( const Vector& pt, const Vector& boxMin, const Vector& boxMax );
  270. // SIMD version
  271. FORCEINLINE bool IsPointInBox( const fltx4& pt, const fltx4& boxMin, const fltx4& boxMax )
  272. {
  273. bi32x4 greater = CmpGtSIMD( pt,boxMax );
  274. bi32x4 less = CmpLtSIMD( pt, boxMin );
  275. return (IsAllZeros(SetWToZeroSIMD(OrSIMD(greater,less))));
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: returns true if pt intersects the truncated cone
  279. // origin - cone tip, axis unit cone axis, cosAngle - cosine of cone axis to surface angle
  280. //-----------------------------------------------------------------------------
  281. bool IsPointInCone( const Vector &pt, const Vector &origin, const Vector &axis, float cosAngle, float length );
  282. //-----------------------------------------------------------------------------
  283. // Intersects a plane with a triangle (using barycentric definition)
  284. // The return value, in pIntersection, is an array of barycentric coordinates
  285. // describing at most 2 intersection points.
  286. // The return value is the number of intersection points
  287. //-----------------------------------------------------------------------------
  288. int IntersectTriangleWithPlaneBarycentric( const Vector& org, const Vector& edgeU, const Vector& edgeV,
  289. const Vector4D& plane, Vector2D* pIntersection );
  290. //-----------------------------------------------------------------------------
  291. //
  292. // PointInQuadBarycentric
  293. //
  294. // Given a point and a quad in a plane return the u and v (barycentric) positions
  295. // of the point relative to the quad. The points (v1,v2,v3,v4) should be given
  296. // in a counter-clockwise order with v1 acting as the primary corner (u=0, v=0).
  297. // Thus, u0 = v2 - v1, and v0 = v4 - v1.
  298. //
  299. //-----------------------------------------------------------------------------
  300. enum QuadBarycentricRetval_t
  301. {
  302. BARY_QUADRATIC_FALSE = 0,
  303. BARY_QUADRATIC_TRUE = 1,
  304. BARY_QUADRATIC_NEGATIVE_DISCRIMINANT = 2
  305. };
  306. QuadBarycentricRetval_t PointInQuadToBarycentric( const Vector &v1, const Vector &v2,
  307. const Vector &v3, const Vector &v4, const Vector &point, Vector2D &uv );
  308. void PointInQuadFromBarycentric( const Vector &v1, const Vector &v2, const Vector &v3, const Vector &v4,
  309. const Vector2D &uv, Vector &point );
  310. void TexCoordInQuadFromBarycentric( const Vector2D &v1, const Vector2D &v2, const Vector2D &v3, const Vector2D &v4,
  311. const Vector2D &uv, Vector2D &texCoord );
  312. //-----------------------------------------------------------------------------
  313. // Compute point from barycentric specification
  314. // Edge u goes from v0 to v1, edge v goes from v0 to v2
  315. //-----------------------------------------------------------------------------
  316. void ComputePointFromBarycentric( const Vector& v0, const Vector& v1, const Vector& v2,
  317. float u, float v, Vector& pt );
  318. void ComputePointFromBarycentric( const Vector2D& v0, const Vector2D& v1, const Vector2D& v2,
  319. float u, float v, Vector2D& pt );
  320. //-----------------------------------------------------------------------------
  321. // Swept OBB test
  322. //-----------------------------------------------------------------------------
  323. bool IsRayIntersectingOBB( const Ray_t &ray, const Vector& org, const QAngle& angles,
  324. const Vector& mins, const Vector& maxs );
  325. //-----------------------------------------------------------------------------
  326. // Compute a separating plane between two boxes (expensive!)
  327. // Returns false if no separating plane exists
  328. //-----------------------------------------------------------------------------
  329. bool ComputeSeparatingPlane( const Vector& org1, const QAngle& angles1, const Vector& min1, const Vector& max1,
  330. const Vector& org2, const QAngle& angles2, const Vector& min2, const Vector& max2,
  331. float tolerance, cplane_t* pPlane );
  332. //-----------------------------------------------------------------------------
  333. // IsBoxIntersectingTriangle
  334. //
  335. // Test for an intersection (overlap) between an axial-aligned bounding
  336. // box (AABB) and a triangle.
  337. //
  338. // Triangle points are in counter-clockwise order with the normal facing "out."
  339. //
  340. // Using the "Separating-Axis Theorem" to test for intersections between
  341. // a triangle and an axial-aligned bounding box (AABB).
  342. // 1. 3 Axis Plane Tests - x, y, z
  343. // 2. 9 Edge Planes Tests - the 3 edges of the triangle crossed with all 3 axial
  344. // planes (x, y, z)
  345. // 3. 1 Face Plane Test - the plane the triangle resides in (cplane_t plane)
  346. //-----------------------------------------------------------------------------
  347. bool IsBoxIntersectingTriangle( const Vector &vecBoxCenter, const Vector &vecBoxExtents,
  348. const Vector &v1, const Vector &v2, const Vector &v3,
  349. const cplane_t &plane, float flTolerance );
  350. Vector CalcClosestPointOnTriangle( const Vector &P, const Vector &v0, const Vector &v1, const Vector &v2 );
  351. //-----------------------------------------------------------------------------
  352. // Compute if the OBB intersects the quad plane, and whether the entire
  353. // OBB/Quad intersection is contained within the quad itself
  354. //
  355. // False if no intersection exists, or if part of the intersection is
  356. // outside the quad's extents
  357. //-----------------------------------------------------------------------------
  358. bool OBBHasFullyContainedIntersectionWithQuad( const Vector &vOBBExtent1_Scaled, const Vector &vOBBExtent2_Scaled, const Vector &vOBBExtent3_Scaled, const Vector &ptOBBCenter,
  359. const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter,
  360. const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length,
  361. const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length );
  362. //-----------------------------------------------------------------------------
  363. // Compute if the Ray intersects the quad plane, and whether the entire
  364. // Ray/Quad intersection is contained within the quad itself
  365. //
  366. // False if no intersection exists, or if part of the intersection is
  367. // outside the quad's extents
  368. //-----------------------------------------------------------------------------
  369. bool RayHasFullyContainedIntersectionWithQuad( const Ray_t &ray,
  370. const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter,
  371. const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length,
  372. const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length );
  373. //-----------------------------------------------------------------------------
  374. // Compute the intersection of a line and a circle
  375. //-----------------------------------------------------------------------------
  376. bool LineCircleIntersection(const Vector2D &center,
  377. const float radius,
  378. const Vector2D &vLinePt,
  379. const Vector2D &vLineDir,
  380. float *fIntersection1,
  381. float *fIntersection2);
  382. //-----------------------------------------------------------------------------
  383. // Find the intersection of a ray with an axis-aligned cylinder
  384. //-----------------------------------------------------------------------------
  385. bool IntersectRayWithAACylinder( const Ray_t &ray,
  386. const Vector &center,
  387. float radius,
  388. float height,
  389. CBaseTrace *pTrace );
  390. //-----------------------------------------------------------------------------
  391. // INLINES
  392. //-----------------------------------------------------------------------------
  393. #ifdef _X360
  394. inline bool IsBoxIntersectingBoxExtents( const fltx4 boxCenter1, const fltx4 boxHalfDiagonal1,
  395. const fltx4 boxCenter2, const fltx4 boxHalfDiagonal2 )
  396. {
  397. fltx4 vecDelta, vecSize;
  398. vecDelta = SubSIMD(boxCenter1, boxCenter2);
  399. vecSize = AddSIMD(boxHalfDiagonal1, boxHalfDiagonal2);
  400. uint condition;
  401. XMVectorInBoundsR(&condition, vecDelta, vecSize);
  402. // we want the top three words to be all 1's ; that means in bounds
  403. return XMComparisonAllInBounds( condition );
  404. }
  405. #endif
  406. #endif // COLLISIONUTILS_H