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.

686 lines
17 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #ifndef VECTOR4D_H
  9. #define VECTOR4D_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include <math.h>
  14. #include <stdlib.h> // For rand(). We really need a library!
  15. #include <float.h>
  16. #if !defined( _X360 )
  17. #include <xmmintrin.h> // For SSE
  18. #endif
  19. #include "basetypes.h" // For vec_t, put this somewhere else?
  20. #include "tier0/dbg.h"
  21. #include "mathlib/math_pfns.h"
  22. // forward declarations
  23. class Vector;
  24. class Vector2D;
  25. //=========================================================
  26. // 4D Vector4D
  27. //=========================================================
  28. class Vector4D
  29. {
  30. public:
  31. // Members
  32. vec_t x, y, z, w;
  33. // Construction/destruction
  34. Vector4D(void);
  35. Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W);
  36. Vector4D(const float *pFloat);
  37. // Initialization
  38. void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f, vec_t iw=0.0f);
  39. // Got any nasty NAN's?
  40. bool IsValid() const;
  41. // array access...
  42. vec_t operator[](int i) const;
  43. vec_t& operator[](int i);
  44. // Base address...
  45. inline vec_t* Base();
  46. inline vec_t const* Base() const;
  47. // Cast to Vector and Vector2D...
  48. Vector& AsVector3D();
  49. Vector const& AsVector3D() const;
  50. Vector2D& AsVector2D();
  51. Vector2D const& AsVector2D() const;
  52. // Initialization methods
  53. void Random( vec_t minVal, vec_t maxVal );
  54. // equality
  55. bool operator==(const Vector4D& v) const;
  56. bool operator!=(const Vector4D& v) const;
  57. // arithmetic operations
  58. Vector4D& operator+=(const Vector4D &v);
  59. Vector4D& operator-=(const Vector4D &v);
  60. Vector4D& operator*=(const Vector4D &v);
  61. Vector4D& operator*=(float s);
  62. Vector4D& operator/=(const Vector4D &v);
  63. Vector4D& operator/=(float s);
  64. // negate the Vector4D components
  65. void Negate();
  66. // Get the Vector4D's magnitude.
  67. vec_t Length() const;
  68. // Get the Vector4D's magnitude squared.
  69. vec_t LengthSqr(void) const;
  70. // return true if this vector is (0,0,0,0) within tolerance
  71. bool IsZero( float tolerance = 0.01f ) const
  72. {
  73. return (x > -tolerance && x < tolerance &&
  74. y > -tolerance && y < tolerance &&
  75. z > -tolerance && z < tolerance &&
  76. w > -tolerance && w < tolerance);
  77. }
  78. // Get the distance from this Vector4D to the other one.
  79. vec_t DistTo(const Vector4D &vOther) const;
  80. // Get the distance from this Vector4D to the other one squared.
  81. vec_t DistToSqr(const Vector4D &vOther) const;
  82. // Copy
  83. void CopyToArray(float* rgfl) const;
  84. // Multiply, add, and assign to this (ie: *this = a + b * scalar). This
  85. // is about 12% faster than the actual Vector4D equation (because it's done per-component
  86. // rather than per-Vector4D).
  87. void MulAdd(Vector4D const& a, Vector4D const& b, float scalar);
  88. // Dot product.
  89. vec_t Dot(Vector4D const& vOther) const;
  90. // No copy constructors allowed if we're in optimal mode
  91. #ifdef VECTOR_NO_SLOW_OPERATIONS
  92. private:
  93. #else
  94. public:
  95. #endif
  96. Vector4D(Vector4D const& vOther);
  97. // No assignment operators either...
  98. Vector4D& operator=( Vector4D const& src );
  99. };
  100. const Vector4D vec4_origin( 0.0f, 0.0f, 0.0f, 0.0f );
  101. const Vector4D vec4_invalid( FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX );
  102. //-----------------------------------------------------------------------------
  103. // SSE optimized routines
  104. //-----------------------------------------------------------------------------
  105. class ALIGN16 Vector4DAligned : public Vector4D
  106. {
  107. public:
  108. Vector4DAligned(void) {}
  109. Vector4DAligned( vec_t X, vec_t Y, vec_t Z, vec_t W );
  110. inline void Set( vec_t X, vec_t Y, vec_t Z, vec_t W );
  111. inline void InitZero( void );
  112. inline __m128 &AsM128() { return *(__m128*)&x; }
  113. inline const __m128 &AsM128() const { return *(const __m128*)&x; }
  114. private:
  115. // No copy constructors allowed if we're in optimal mode
  116. Vector4DAligned( Vector4DAligned const& vOther );
  117. // No assignment operators either...
  118. Vector4DAligned& operator=( Vector4DAligned const& src );
  119. } ALIGN16_POST;
  120. //-----------------------------------------------------------------------------
  121. // Vector4D related operations
  122. //-----------------------------------------------------------------------------
  123. // Vector4D clear
  124. void Vector4DClear( Vector4D& a );
  125. // Copy
  126. void Vector4DCopy( Vector4D const& src, Vector4D& dst );
  127. // Vector4D arithmetic
  128. void Vector4DAdd( Vector4D const& a, Vector4D const& b, Vector4D& result );
  129. void Vector4DSubtract( Vector4D const& a, Vector4D const& b, Vector4D& result );
  130. void Vector4DMultiply( Vector4D const& a, vec_t b, Vector4D& result );
  131. void Vector4DMultiply( Vector4D const& a, Vector4D const& b, Vector4D& result );
  132. void Vector4DDivide( Vector4D const& a, vec_t b, Vector4D& result );
  133. void Vector4DDivide( Vector4D const& a, Vector4D const& b, Vector4D& result );
  134. void Vector4DMA( Vector4D const& start, float s, Vector4D const& dir, Vector4D& result );
  135. // Vector4DAligned arithmetic
  136. void Vector4DMultiplyAligned( Vector4DAligned const& a, vec_t b, Vector4DAligned& result );
  137. #define Vector4DExpand( v ) (v).x, (v).y, (v).z, (v).w
  138. // Normalization
  139. vec_t Vector4DNormalize( Vector4D& v );
  140. // Length
  141. vec_t Vector4DLength( Vector4D const& v );
  142. // Dot Product
  143. vec_t DotProduct4D(Vector4D const& a, Vector4D const& b);
  144. // Linearly interpolate between two vectors
  145. void Vector4DLerp(Vector4D const& src1, Vector4D const& src2, vec_t t, Vector4D& dest );
  146. //-----------------------------------------------------------------------------
  147. //
  148. // Inlined Vector4D methods
  149. //
  150. //-----------------------------------------------------------------------------
  151. //-----------------------------------------------------------------------------
  152. // constructors
  153. //-----------------------------------------------------------------------------
  154. inline Vector4D::Vector4D(void)
  155. {
  156. #ifdef _DEBUG
  157. // Initialize to NAN to catch errors
  158. x = y = z = w = VEC_T_NAN;
  159. #endif
  160. }
  161. inline Vector4D::Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W )
  162. {
  163. x = X; y = Y; z = Z; w = W;
  164. Assert( IsValid() );
  165. }
  166. inline Vector4D::Vector4D(const float *pFloat)
  167. {
  168. Assert( pFloat );
  169. x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; w = pFloat[3];
  170. Assert( IsValid() );
  171. }
  172. //-----------------------------------------------------------------------------
  173. // copy constructor
  174. //-----------------------------------------------------------------------------
  175. inline Vector4D::Vector4D(const Vector4D &vOther)
  176. {
  177. Assert( vOther.IsValid() );
  178. x = vOther.x; y = vOther.y; z = vOther.z; w = vOther.w;
  179. }
  180. //-----------------------------------------------------------------------------
  181. // initialization
  182. //-----------------------------------------------------------------------------
  183. inline void Vector4D::Init( vec_t ix, vec_t iy, vec_t iz, vec_t iw )
  184. {
  185. x = ix; y = iy; z = iz; w = iw;
  186. Assert( IsValid() );
  187. }
  188. inline void Vector4D::Random( vec_t minVal, vec_t maxVal )
  189. {
  190. x = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
  191. y = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
  192. z = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
  193. w = minVal + ((vec_t)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
  194. }
  195. inline void Vector4DClear( Vector4D& a )
  196. {
  197. a.x = a.y = a.z = a.w = 0.0f;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // assignment
  201. //-----------------------------------------------------------------------------
  202. inline Vector4D& Vector4D::operator=(const Vector4D &vOther)
  203. {
  204. Assert( vOther.IsValid() );
  205. x=vOther.x; y=vOther.y; z=vOther.z; w=vOther.w;
  206. return *this;
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Array access
  210. //-----------------------------------------------------------------------------
  211. inline vec_t& Vector4D::operator[](int i)
  212. {
  213. Assert( (i >= 0) && (i < 4) );
  214. return ((vec_t*)this)[i];
  215. }
  216. inline vec_t Vector4D::operator[](int i) const
  217. {
  218. Assert( (i >= 0) && (i < 4) );
  219. return ((vec_t*)this)[i];
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Cast to Vector and Vector2D...
  223. //-----------------------------------------------------------------------------
  224. inline Vector& Vector4D::AsVector3D()
  225. {
  226. return *(Vector*)this;
  227. }
  228. inline Vector const& Vector4D::AsVector3D() const
  229. {
  230. return *(Vector const*)this;
  231. }
  232. inline Vector2D& Vector4D::AsVector2D()
  233. {
  234. return *(Vector2D*)this;
  235. }
  236. inline Vector2D const& Vector4D::AsVector2D() const
  237. {
  238. return *(Vector2D const*)this;
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Base address...
  242. //-----------------------------------------------------------------------------
  243. inline vec_t* Vector4D::Base()
  244. {
  245. return (vec_t*)this;
  246. }
  247. inline vec_t const* Vector4D::Base() const
  248. {
  249. return (vec_t const*)this;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // IsValid?
  253. //-----------------------------------------------------------------------------
  254. inline bool Vector4D::IsValid() const
  255. {
  256. return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w);
  257. }
  258. //-----------------------------------------------------------------------------
  259. // comparison
  260. //-----------------------------------------------------------------------------
  261. inline bool Vector4D::operator==( Vector4D const& src ) const
  262. {
  263. Assert( src.IsValid() && IsValid() );
  264. return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w);
  265. }
  266. inline bool Vector4D::operator!=( Vector4D const& src ) const
  267. {
  268. Assert( src.IsValid() && IsValid() );
  269. return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w);
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Copy
  273. //-----------------------------------------------------------------------------
  274. inline void Vector4DCopy( Vector4D const& src, Vector4D& dst )
  275. {
  276. Assert( src.IsValid() );
  277. dst.x = src.x;
  278. dst.y = src.y;
  279. dst.z = src.z;
  280. dst.w = src.w;
  281. }
  282. inline void Vector4D::CopyToArray(float* rgfl) const
  283. {
  284. Assert( IsValid() );
  285. Assert( rgfl );
  286. rgfl[0] = x; rgfl[1] = y; rgfl[2] = z; rgfl[3] = w;
  287. }
  288. //-----------------------------------------------------------------------------
  289. // standard math operations
  290. //-----------------------------------------------------------------------------
  291. inline void Vector4D::Negate()
  292. {
  293. Assert( IsValid() );
  294. x = -x; y = -y; z = -z; w = -w;
  295. }
  296. inline Vector4D& Vector4D::operator+=(const Vector4D& v)
  297. {
  298. Assert( IsValid() && v.IsValid() );
  299. x+=v.x; y+=v.y; z += v.z; w += v.w;
  300. return *this;
  301. }
  302. inline Vector4D& Vector4D::operator-=(const Vector4D& v)
  303. {
  304. Assert( IsValid() && v.IsValid() );
  305. x-=v.x; y-=v.y; z -= v.z; w -= v.w;
  306. return *this;
  307. }
  308. inline Vector4D& Vector4D::operator*=(float fl)
  309. {
  310. x *= fl;
  311. y *= fl;
  312. z *= fl;
  313. w *= fl;
  314. Assert( IsValid() );
  315. return *this;
  316. }
  317. inline Vector4D& Vector4D::operator*=(Vector4D const& v)
  318. {
  319. x *= v.x;
  320. y *= v.y;
  321. z *= v.z;
  322. w *= v.w;
  323. Assert( IsValid() );
  324. return *this;
  325. }
  326. inline Vector4D& Vector4D::operator/=(float fl)
  327. {
  328. Assert( fl != 0.0f );
  329. float oofl = 1.0f / fl;
  330. x *= oofl;
  331. y *= oofl;
  332. z *= oofl;
  333. w *= oofl;
  334. Assert( IsValid() );
  335. return *this;
  336. }
  337. inline Vector4D& Vector4D::operator/=(Vector4D const& v)
  338. {
  339. Assert( v.x != 0.0f && v.y != 0.0f && v.z != 0.0f && v.w != 0.0f );
  340. x /= v.x;
  341. y /= v.y;
  342. z /= v.z;
  343. w /= v.w;
  344. Assert( IsValid() );
  345. return *this;
  346. }
  347. inline void Vector4DAdd( Vector4D const& a, Vector4D const& b, Vector4D& c )
  348. {
  349. Assert( a.IsValid() && b.IsValid() );
  350. c.x = a.x + b.x;
  351. c.y = a.y + b.y;
  352. c.z = a.z + b.z;
  353. c.w = a.w + b.w;
  354. }
  355. inline void Vector4DSubtract( Vector4D const& a, Vector4D const& b, Vector4D& c )
  356. {
  357. Assert( a.IsValid() && b.IsValid() );
  358. c.x = a.x - b.x;
  359. c.y = a.y - b.y;
  360. c.z = a.z - b.z;
  361. c.w = a.w - b.w;
  362. }
  363. inline void Vector4DMultiply( Vector4D const& a, vec_t b, Vector4D& c )
  364. {
  365. Assert( a.IsValid() && IsFinite(b) );
  366. c.x = a.x * b;
  367. c.y = a.y * b;
  368. c.z = a.z * b;
  369. c.w = a.w * b;
  370. }
  371. inline void Vector4DMultiply( Vector4D const& a, Vector4D const& b, Vector4D& c )
  372. {
  373. Assert( a.IsValid() && b.IsValid() );
  374. c.x = a.x * b.x;
  375. c.y = a.y * b.y;
  376. c.z = a.z * b.z;
  377. c.w = a.w * b.w;
  378. }
  379. inline void Vector4DDivide( Vector4D const& a, vec_t b, Vector4D& c )
  380. {
  381. Assert( a.IsValid() );
  382. Assert( b != 0.0f );
  383. vec_t oob = 1.0f / b;
  384. c.x = a.x * oob;
  385. c.y = a.y * oob;
  386. c.z = a.z * oob;
  387. c.w = a.w * oob;
  388. }
  389. inline void Vector4DDivide( Vector4D const& a, Vector4D const& b, Vector4D& c )
  390. {
  391. Assert( a.IsValid() );
  392. Assert( (b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f) && (b.w != 0.0f) );
  393. c.x = a.x / b.x;
  394. c.y = a.y / b.y;
  395. c.z = a.z / b.z;
  396. c.w = a.w / b.w;
  397. }
  398. inline void Vector4DMA( Vector4D const& start, float s, Vector4D const& dir, Vector4D& result )
  399. {
  400. Assert( start.IsValid() && IsFinite(s) && dir.IsValid() );
  401. result.x = start.x + s*dir.x;
  402. result.y = start.y + s*dir.y;
  403. result.z = start.z + s*dir.z;
  404. result.w = start.w + s*dir.w;
  405. }
  406. // FIXME: Remove
  407. // For backwards compatability
  408. inline void Vector4D::MulAdd(Vector4D const& a, Vector4D const& b, float scalar)
  409. {
  410. x = a.x + b.x * scalar;
  411. y = a.y + b.y * scalar;
  412. z = a.z + b.z * scalar;
  413. w = a.w + b.w * scalar;
  414. }
  415. inline void Vector4DLerp(const Vector4D& src1, const Vector4D& src2, vec_t t, Vector4D& dest )
  416. {
  417. dest[0] = src1[0] + (src2[0] - src1[0]) * t;
  418. dest[1] = src1[1] + (src2[1] - src1[1]) * t;
  419. dest[2] = src1[2] + (src2[2] - src1[2]) * t;
  420. dest[3] = src1[3] + (src2[3] - src1[3]) * t;
  421. }
  422. //-----------------------------------------------------------------------------
  423. // dot, cross
  424. //-----------------------------------------------------------------------------
  425. inline vec_t DotProduct4D(const Vector4D& a, const Vector4D& b)
  426. {
  427. Assert( a.IsValid() && b.IsValid() );
  428. return( a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w );
  429. }
  430. // for backwards compatability
  431. inline vec_t Vector4D::Dot( Vector4D const& vOther ) const
  432. {
  433. return DotProduct4D( *this, vOther );
  434. }
  435. //-----------------------------------------------------------------------------
  436. // length
  437. //-----------------------------------------------------------------------------
  438. inline vec_t Vector4DLength( Vector4D const& v )
  439. {
  440. Assert( v.IsValid() );
  441. return (vec_t)FastSqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w);
  442. }
  443. inline vec_t Vector4D::LengthSqr(void) const
  444. {
  445. Assert( IsValid() );
  446. return (x*x + y*y + z*z + w*w);
  447. }
  448. inline vec_t Vector4D::Length(void) const
  449. {
  450. return Vector4DLength( *this );
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Normalization
  454. //-----------------------------------------------------------------------------
  455. // FIXME: Can't use until we're un-macroed in mathlib.h
  456. inline vec_t Vector4DNormalize( Vector4D& v )
  457. {
  458. Assert( v.IsValid() );
  459. vec_t l = v.Length();
  460. if (l != 0.0f)
  461. {
  462. v /= l;
  463. }
  464. else
  465. {
  466. v.x = v.y = v.z = v.w = 0.0f;
  467. }
  468. return l;
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Get the distance from this Vector4D to the other one
  472. //-----------------------------------------------------------------------------
  473. inline vec_t Vector4D::DistTo(const Vector4D &vOther) const
  474. {
  475. Vector4D delta;
  476. Vector4DSubtract( *this, vOther, delta );
  477. return delta.Length();
  478. }
  479. inline vec_t Vector4D::DistToSqr(const Vector4D &vOther) const
  480. {
  481. Vector4D delta;
  482. Vector4DSubtract( *this, vOther, delta );
  483. return delta.LengthSqr();
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Vector4DAligned routines
  487. //-----------------------------------------------------------------------------
  488. inline Vector4DAligned::Vector4DAligned( vec_t X, vec_t Y, vec_t Z, vec_t W )
  489. {
  490. x = X; y = Y; z = Z; w = W;
  491. Assert( IsValid() );
  492. }
  493. inline void Vector4DAligned::Set( vec_t X, vec_t Y, vec_t Z, vec_t W )
  494. {
  495. x = X; y = Y; z = Z; w = W;
  496. Assert( IsValid() );
  497. }
  498. inline void Vector4DAligned::InitZero( void )
  499. {
  500. #if !defined( _X360 )
  501. this->AsM128() = _mm_set1_ps( 0.0f );
  502. #else
  503. this->AsM128() = __vspltisw( 0 );
  504. #endif
  505. Assert( IsValid() );
  506. }
  507. inline void Vector4DMultiplyAligned( Vector4DAligned const& a, Vector4DAligned const& b, Vector4DAligned& c )
  508. {
  509. Assert( a.IsValid() && b.IsValid() );
  510. #if !defined( _X360 )
  511. c.x = a.x * b.x;
  512. c.y = a.y * b.y;
  513. c.z = a.z * b.z;
  514. c.w = a.w * b.w;
  515. #else
  516. c.AsM128() = __vmulfp( a.AsM128(), b.AsM128() );
  517. #endif
  518. }
  519. inline void Vector4DWeightMAD( vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB )
  520. {
  521. Assert( vInA.IsValid() && vInB.IsValid() && IsFinite(w) );
  522. #if !defined( _X360 )
  523. vOutA.x += vInA.x * w;
  524. vOutA.y += vInA.y * w;
  525. vOutA.z += vInA.z * w;
  526. vOutA.w += vInA.w * w;
  527. vOutB.x += vInB.x * w;
  528. vOutB.y += vInB.y * w;
  529. vOutB.z += vInB.z * w;
  530. vOutB.w += vInB.w * w;
  531. #else
  532. __vector4 temp;
  533. temp = __lvlx( &w, 0 );
  534. temp = __vspltw( temp, 0 );
  535. vOutA.AsM128() = __vmaddfp( vInA.AsM128(), temp, vOutA.AsM128() );
  536. vOutB.AsM128() = __vmaddfp( vInB.AsM128(), temp, vOutB.AsM128() );
  537. #endif
  538. }
  539. inline void Vector4DWeightMADSSE( vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB )
  540. {
  541. Assert( vInA.IsValid() && vInB.IsValid() && IsFinite(w) );
  542. #if !defined( _X360 )
  543. // Replicate scalar float out to 4 components
  544. __m128 packed = _mm_set1_ps( w );
  545. // 4D SSE Vector MAD
  546. vOutA.AsM128() = _mm_add_ps( vOutA.AsM128(), _mm_mul_ps( vInA.AsM128(), packed ) );
  547. vOutB.AsM128() = _mm_add_ps( vOutB.AsM128(), _mm_mul_ps( vInB.AsM128(), packed ) );
  548. #else
  549. __vector4 temp;
  550. temp = __lvlx( &w, 0 );
  551. temp = __vspltw( temp, 0 );
  552. vOutA.AsM128() = __vmaddfp( vInA.AsM128(), temp, vOutA.AsM128() );
  553. vOutB.AsM128() = __vmaddfp( vInB.AsM128(), temp, vOutB.AsM128() );
  554. #endif
  555. }
  556. #endif // VECTOR4D_H