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.

2187 lines
66 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifndef MATH_LIB_H
  7. #define MATH_LIB_H
  8. #include <math.h>
  9. #include "minmax.h"
  10. #include "tier0/basetypes.h"
  11. #include "tier0/commonmacros.h"
  12. #include "mathlib/vector.h"
  13. #include "mathlib/vector2d.h"
  14. #include "tier0/dbg.h"
  15. #include "mathlib/math_pfns.h"
  16. #if defined(__i386__) || defined(_M_IX86)
  17. // For MMX intrinsics
  18. #include <xmmintrin.h>
  19. #endif
  20. // XXX remove me
  21. #undef clamp
  22. // Uncomment this to enable FP exceptions in parts of the code.
  23. // This can help track down FP bugs. However the code is not
  24. // FP exception clean so this not a turnkey operation.
  25. //#define FP_EXCEPTIONS_ENABLED
  26. #ifdef FP_EXCEPTIONS_ENABLED
  27. #include <float.h> // For _clearfp and _controlfp_s
  28. #endif
  29. // FPExceptionDisabler and FPExceptionEnabler taken from my blog post
  30. // at http://www.altdevblogaday.com/2012/04/20/exceptional-floating-point/
  31. // Declare an object of this type in a scope in order to suppress
  32. // all floating-point exceptions temporarily. The old exception
  33. // state will be reset at the end.
  34. class FPExceptionDisabler
  35. {
  36. public:
  37. #ifdef FP_EXCEPTIONS_ENABLED
  38. FPExceptionDisabler();
  39. ~FPExceptionDisabler();
  40. private:
  41. unsigned int mOldValues;
  42. #else
  43. FPExceptionDisabler() {}
  44. ~FPExceptionDisabler() {}
  45. #endif
  46. private:
  47. // Make the copy constructor and assignment operator private
  48. // and unimplemented to prohibit copying.
  49. FPExceptionDisabler(const FPExceptionDisabler&);
  50. FPExceptionDisabler& operator=(const FPExceptionDisabler&);
  51. };
  52. // Declare an object of this type in a scope in order to enable a
  53. // specified set of floating-point exceptions temporarily. The old
  54. // exception state will be reset at the end.
  55. // This class can be nested.
  56. class FPExceptionEnabler
  57. {
  58. public:
  59. // Overflow, divide-by-zero, and invalid-operation are the FP
  60. // exceptions most frequently associated with bugs.
  61. #ifdef FP_EXCEPTIONS_ENABLED
  62. FPExceptionEnabler(unsigned int enableBits = _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID);
  63. ~FPExceptionEnabler();
  64. private:
  65. unsigned int mOldValues;
  66. #else
  67. FPExceptionEnabler(unsigned int enableBits = 0)
  68. {
  69. }
  70. ~FPExceptionEnabler()
  71. {
  72. }
  73. #endif
  74. private:
  75. // Make the copy constructor and assignment operator private
  76. // and unimplemented to prohibit copying.
  77. FPExceptionEnabler(const FPExceptionEnabler&);
  78. FPExceptionEnabler& operator=(const FPExceptionEnabler&);
  79. };
  80. #ifdef DEBUG // stop crashing edit-and-continue
  81. FORCEINLINE float clamp( float val, float minVal, float maxVal )
  82. {
  83. if ( maxVal < minVal )
  84. return maxVal;
  85. else if( val < minVal )
  86. return minVal;
  87. else if( val > maxVal )
  88. return maxVal;
  89. else
  90. return val;
  91. }
  92. #else // DEBUG
  93. FORCEINLINE float clamp( float val, float minVal, float maxVal )
  94. {
  95. #if defined(__i386__) || defined(_M_IX86)
  96. _mm_store_ss( &val,
  97. _mm_min_ss(
  98. _mm_max_ss(
  99. _mm_load_ss(&val),
  100. _mm_load_ss(&minVal) ),
  101. _mm_load_ss(&maxVal) ) );
  102. #else
  103. val = fpmax(minVal, val);
  104. val = fpmin(maxVal, val);
  105. #endif
  106. return val;
  107. }
  108. #endif // DEBUG
  109. //
  110. // Returns a clamped value in the range [min, max].
  111. //
  112. template< class T >
  113. inline T clamp( T const &val, T const &minVal, T const &maxVal )
  114. {
  115. if ( maxVal < minVal )
  116. return maxVal;
  117. else if( val < minVal )
  118. return minVal;
  119. else if( val > maxVal )
  120. return maxVal;
  121. else
  122. return val;
  123. }
  124. // plane_t structure
  125. // !!! if this is changed, it must be changed in asm code too !!!
  126. // FIXME: does the asm code even exist anymore?
  127. // FIXME: this should move to a different file
  128. struct cplane_t
  129. {
  130. Vector normal;
  131. float dist;
  132. byte type; // for fast side tests
  133. byte signbits; // signx + (signy<<1) + (signz<<1)
  134. byte pad[2];
  135. #ifdef VECTOR_NO_SLOW_OPERATIONS
  136. cplane_t() {}
  137. private:
  138. // No copy constructors allowed if we're in optimal mode
  139. cplane_t(const cplane_t& vOther);
  140. #endif
  141. };
  142. // structure offset for asm code
  143. #define CPLANE_NORMAL_X 0
  144. #define CPLANE_NORMAL_Y 4
  145. #define CPLANE_NORMAL_Z 8
  146. #define CPLANE_DIST 12
  147. #define CPLANE_TYPE 16
  148. #define CPLANE_SIGNBITS 17
  149. #define CPLANE_PAD0 18
  150. #define CPLANE_PAD1 19
  151. // 0-2 are axial planes
  152. #define PLANE_X 0
  153. #define PLANE_Y 1
  154. #define PLANE_Z 2
  155. // 3-5 are non-axial planes snapped to the nearest
  156. #define PLANE_ANYX 3
  157. #define PLANE_ANYY 4
  158. #define PLANE_ANYZ 5
  159. //-----------------------------------------------------------------------------
  160. // Frustum plane indices.
  161. // WARNING: there is code that depends on these values
  162. //-----------------------------------------------------------------------------
  163. enum
  164. {
  165. FRUSTUM_RIGHT = 0,
  166. FRUSTUM_LEFT = 1,
  167. FRUSTUM_TOP = 2,
  168. FRUSTUM_BOTTOM = 3,
  169. FRUSTUM_NEARZ = 4,
  170. FRUSTUM_FARZ = 5,
  171. FRUSTUM_NUMPLANES = 6
  172. };
  173. extern int SignbitsForPlane( cplane_t *out );
  174. class Frustum_t
  175. {
  176. public:
  177. void SetPlane( int i, int nType, const Vector &vecNormal, float dist )
  178. {
  179. m_Plane[i].normal = vecNormal;
  180. m_Plane[i].dist = dist;
  181. m_Plane[i].type = nType;
  182. m_Plane[i].signbits = SignbitsForPlane( &m_Plane[i] );
  183. m_AbsNormal[i].Init( fabs(vecNormal.x), fabs(vecNormal.y), fabs(vecNormal.z) );
  184. }
  185. inline const cplane_t *GetPlane( int i ) const { return &m_Plane[i]; }
  186. inline const Vector &GetAbsNormal( int i ) const { return m_AbsNormal[i]; }
  187. private:
  188. cplane_t m_Plane[FRUSTUM_NUMPLANES];
  189. Vector m_AbsNormal[FRUSTUM_NUMPLANES];
  190. };
  191. // Computes Y fov from an X fov and a screen aspect ratio + X from Y
  192. float CalcFovY( float flFovX, float flScreenAspect );
  193. float CalcFovX( float flFovY, float flScreenAspect );
  194. // Generate a frustum based on perspective view parameters
  195. // NOTE: FOV is specified in degrees, as the *full* view angle (not half-angle)
  196. void GeneratePerspectiveFrustum( const Vector& origin, const QAngle &angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t &frustum );
  197. void GeneratePerspectiveFrustum( const Vector& origin, const Vector &forward, const Vector &right, const Vector &up, float flZNear, float flZFar, float flFovX, float flFovY, Frustum_t &frustum );
  198. // Cull the world-space bounding box to the specified frustum.
  199. bool R_CullBox( const Vector& mins, const Vector& maxs, const Frustum_t &frustum );
  200. bool R_CullBoxSkipNear( const Vector& mins, const Vector& maxs, const Frustum_t &frustum );
  201. struct matrix3x4_t
  202. {
  203. matrix3x4_t() {}
  204. matrix3x4_t(
  205. float m00, float m01, float m02, float m03,
  206. float m10, float m11, float m12, float m13,
  207. float m20, float m21, float m22, float m23 )
  208. {
  209. m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03;
  210. m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13;
  211. m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Creates a matrix where the X axis = forward
  215. // the Y axis = left, and the Z axis = up
  216. //-----------------------------------------------------------------------------
  217. void Init( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
  218. {
  219. m_flMatVal[0][0] = xAxis.x; m_flMatVal[0][1] = yAxis.x; m_flMatVal[0][2] = zAxis.x; m_flMatVal[0][3] = vecOrigin.x;
  220. m_flMatVal[1][0] = xAxis.y; m_flMatVal[1][1] = yAxis.y; m_flMatVal[1][2] = zAxis.y; m_flMatVal[1][3] = vecOrigin.y;
  221. m_flMatVal[2][0] = xAxis.z; m_flMatVal[2][1] = yAxis.z; m_flMatVal[2][2] = zAxis.z; m_flMatVal[2][3] = vecOrigin.z;
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Creates a matrix where the X axis = forward
  225. // the Y axis = left, and the Z axis = up
  226. //-----------------------------------------------------------------------------
  227. matrix3x4_t( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
  228. {
  229. Init( xAxis, yAxis, zAxis, vecOrigin );
  230. }
  231. inline void Invalidate( void )
  232. {
  233. for (int i = 0; i < 3; i++)
  234. {
  235. for (int j = 0; j < 4; j++)
  236. {
  237. m_flMatVal[i][j] = VEC_T_NAN;
  238. }
  239. }
  240. }
  241. float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; }
  242. const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; }
  243. float *Base() { return &m_flMatVal[0][0]; }
  244. const float *Base() const { return &m_flMatVal[0][0]; }
  245. float m_flMatVal[3][4];
  246. };
  247. #ifndef M_PI
  248. #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
  249. #endif
  250. #define M_PI_F ((float)(M_PI)) // Shouldn't collide with anything.
  251. // NJS: Inlined to prevent floats from being autopromoted to doubles, as with the old system.
  252. #ifndef RAD2DEG
  253. #define RAD2DEG( x ) ( (float)(x) * (float)(180.f / M_PI_F) )
  254. #endif
  255. #ifndef DEG2RAD
  256. #define DEG2RAD( x ) ( (float)(x) * (float)(M_PI_F / 180.f) )
  257. #endif
  258. // Used to represent sides of things like planes.
  259. #define SIDE_FRONT 0
  260. #define SIDE_BACK 1
  261. #define SIDE_ON 2
  262. #define SIDE_CROSS -2 // necessary for polylib.c
  263. #define ON_VIS_EPSILON 0.01 // necessary for vvis (flow.c) -- again look into moving later!
  264. #define EQUAL_EPSILON 0.001 // necessary for vbsp (faces.c) -- should look into moving it there?
  265. extern bool s_bMathlibInitialized;
  266. extern const Vector vec3_origin;
  267. extern const QAngle vec3_angle;
  268. extern const Quaternion quat_identity;
  269. extern const Vector vec3_invalid;
  270. extern const int nanmask;
  271. #define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
  272. FORCEINLINE vec_t DotProduct(const vec_t *v1, const vec_t *v2)
  273. {
  274. return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
  275. }
  276. FORCEINLINE void VectorSubtract(const vec_t *a, const vec_t *b, vec_t *c)
  277. {
  278. c[0]=a[0]-b[0];
  279. c[1]=a[1]-b[1];
  280. c[2]=a[2]-b[2];
  281. }
  282. FORCEINLINE void VectorAdd(const vec_t *a, const vec_t *b, vec_t *c)
  283. {
  284. c[0]=a[0]+b[0];
  285. c[1]=a[1]+b[1];
  286. c[2]=a[2]+b[2];
  287. }
  288. FORCEINLINE void VectorCopy(const vec_t *a, vec_t *b)
  289. {
  290. b[0]=a[0];
  291. b[1]=a[1];
  292. b[2]=a[2];
  293. }
  294. FORCEINLINE void VectorClear(vec_t *a)
  295. {
  296. a[0]=a[1]=a[2]=0;
  297. }
  298. FORCEINLINE float VectorMaximum(const vec_t *v)
  299. {
  300. return max( v[0], max( v[1], v[2] ) );
  301. }
  302. FORCEINLINE float VectorMaximum(const Vector& v)
  303. {
  304. return max( v.x, max( v.y, v.z ) );
  305. }
  306. FORCEINLINE void VectorScale (const float* in, vec_t scale, float* out)
  307. {
  308. out[0] = in[0]*scale;
  309. out[1] = in[1]*scale;
  310. out[2] = in[2]*scale;
  311. }
  312. // Cannot be forceinline as they have overloads:
  313. inline void VectorFill(vec_t *a, float b)
  314. {
  315. a[0]=a[1]=a[2]=b;
  316. }
  317. inline void VectorNegate(vec_t *a)
  318. {
  319. a[0]=-a[0];
  320. a[1]=-a[1];
  321. a[2]=-a[2];
  322. }
  323. //#define VectorMaximum(a) ( max( (a)[0], max( (a)[1], (a)[2] ) ) )
  324. #define Vector2Clear(x) {(x)[0]=(x)[1]=0;}
  325. #define Vector2Negate(x) {(x)[0]=-((x)[0]);(x)[1]=-((x)[1]);}
  326. #define Vector2Copy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];}
  327. #define Vector2Subtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];}
  328. #define Vector2Add(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];}
  329. #define Vector2Scale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];}
  330. // NJS: Some functions in VBSP still need to use these for dealing with mixing vec4's and shorts with vec_t's.
  331. // remove when no longer needed.
  332. #define VECTOR_COPY( A, B ) do { (B)[0] = (A)[0]; (B)[1] = (A)[1]; (B)[2]=(A)[2]; } while(0)
  333. #define DOT_PRODUCT( A, B ) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] )
  334. FORCEINLINE void VectorMAInline( const float* start, float scale, const float* direction, float* dest )
  335. {
  336. dest[0]=start[0]+direction[0]*scale;
  337. dest[1]=start[1]+direction[1]*scale;
  338. dest[2]=start[2]+direction[2]*scale;
  339. }
  340. FORCEINLINE void VectorMAInline( const Vector& start, float scale, const Vector& direction, Vector& dest )
  341. {
  342. dest.x=start.x+direction.x*scale;
  343. dest.y=start.y+direction.y*scale;
  344. dest.z=start.z+direction.z*scale;
  345. }
  346. FORCEINLINE void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest )
  347. {
  348. VectorMAInline(start, scale, direction, dest);
  349. }
  350. FORCEINLINE void VectorMA( const float * start, float scale, const float *direction, float *dest )
  351. {
  352. VectorMAInline(start, scale, direction, dest);
  353. }
  354. int VectorCompare (const float *v1, const float *v2);
  355. inline float VectorLength(const float *v)
  356. {
  357. return FastSqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + FLT_EPSILON );
  358. }
  359. void CrossProduct (const float *v1, const float *v2, float *cross);
  360. qboolean VectorsEqual( const float *v1, const float *v2 );
  361. inline vec_t RoundInt (vec_t in)
  362. {
  363. return floor(in + 0.5f);
  364. }
  365. int Q_log2(int val);
  366. // Math routines done in optimized assembly math package routines
  367. void inline SinCos( float radians, float *sine, float *cosine )
  368. {
  369. #if defined( _X360 )
  370. XMScalarSinCos( sine, cosine, radians );
  371. #elif defined( PLATFORM_WINDOWS_PC32 )
  372. _asm
  373. {
  374. fld DWORD PTR [radians]
  375. fsincos
  376. mov edx, DWORD PTR [cosine]
  377. mov eax, DWORD PTR [sine]
  378. fstp DWORD PTR [edx]
  379. fstp DWORD PTR [eax]
  380. }
  381. #elif defined( PLATFORM_WINDOWS_PC64 )
  382. *sine = sin( radians );
  383. *cosine = cos( radians );
  384. #elif defined( POSIX )
  385. double __cosr, __sinr;
  386. __asm ("fsincos" : "=t" (__cosr), "=u" (__sinr) : "0" (radians));
  387. *sine = __sinr;
  388. *cosine = __cosr;
  389. #endif
  390. }
  391. #define SIN_TABLE_SIZE 256
  392. #define FTOIBIAS 12582912.f
  393. extern float SinCosTable[SIN_TABLE_SIZE];
  394. inline float TableCos( float theta )
  395. {
  396. union
  397. {
  398. int i;
  399. float f;
  400. } ftmp;
  401. // ideally, the following should compile down to: theta * constant + constant, changing any of these constants from defines sometimes fubars this.
  402. ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + ( FTOIBIAS + ( SIN_TABLE_SIZE / 4 ) );
  403. return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ];
  404. }
  405. inline float TableSin( float theta )
  406. {
  407. union
  408. {
  409. int i;
  410. float f;
  411. } ftmp;
  412. // ideally, the following should compile down to: theta * constant + constant
  413. ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + FTOIBIAS;
  414. return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ];
  415. }
  416. template<class T>
  417. FORCEINLINE T Square( T const &a )
  418. {
  419. return a * a;
  420. }
  421. // return the smallest power of two >= x.
  422. // returns 0 if x == 0 or x > 0x80000000 (ie numbers that would be negative if x was signed)
  423. // NOTE: the old code took an int, and if you pass in an int of 0x80000000 casted to a uint,
  424. // you'll get 0x80000000, which is correct for uints, instead of 0, which was correct for ints
  425. FORCEINLINE uint SmallestPowerOfTwoGreaterOrEqual( uint x )
  426. {
  427. x -= 1;
  428. x |= x >> 1;
  429. x |= x >> 2;
  430. x |= x >> 4;
  431. x |= x >> 8;
  432. x |= x >> 16;
  433. return x + 1;
  434. }
  435. // return the largest power of two <= x. Will return 0 if passed 0
  436. FORCEINLINE uint LargestPowerOfTwoLessThanOrEqual( uint x )
  437. {
  438. if ( x >= 0x80000000 )
  439. return 0x80000000;
  440. return SmallestPowerOfTwoGreaterOrEqual( x + 1 ) >> 1;
  441. }
  442. // Math routines for optimizing division
  443. void FloorDivMod (double numer, double denom, int *quotient, int *rem);
  444. int GreatestCommonDivisor (int i1, int i2);
  445. // Test for FPU denormal mode
  446. bool IsDenormal( const float &val );
  447. // MOVEMENT INFO
  448. enum
  449. {
  450. PITCH = 0, // up / down
  451. YAW, // left / right
  452. ROLL // fall over
  453. };
  454. void MatrixAngles( const matrix3x4_t & matrix, float *angles ); // !!!!
  455. void MatrixVectors( const matrix3x4_t &matrix, Vector* pForward, Vector *pRight, Vector *pUp );
  456. void VectorTransform (const float *in1, const matrix3x4_t & in2, float *out);
  457. void VectorITransform (const float *in1, const matrix3x4_t & in2, float *out);
  458. void VectorRotate( const float *in1, const matrix3x4_t & in2, float *out);
  459. void VectorRotate( const Vector &in1, const QAngle &in2, Vector &out );
  460. void VectorRotate( const Vector &in1, const Quaternion &in2, Vector &out );
  461. void VectorIRotate( const float *in1, const matrix3x4_t & in2, float *out);
  462. #ifndef VECTOR_NO_SLOW_OPERATIONS
  463. QAngle TransformAnglesToLocalSpace( const QAngle &angles, const matrix3x4_t &parentMatrix );
  464. QAngle TransformAnglesToWorldSpace( const QAngle &angles, const matrix3x4_t &parentMatrix );
  465. #endif
  466. void MatrixInitialize( matrix3x4_t &mat, const Vector &vecOrigin, const Vector &vecXAxis, const Vector &vecYAxis, const Vector &vecZAxis );
  467. void MatrixCopy( const matrix3x4_t &in, matrix3x4_t &out );
  468. void MatrixInvert( const matrix3x4_t &in, matrix3x4_t &out );
  469. // Matrix equality test
  470. bool MatricesAreEqual( const matrix3x4_t &src1, const matrix3x4_t &src2, float flTolerance = 1e-5 );
  471. void MatrixGetColumn( const matrix3x4_t &in, int column, Vector &out );
  472. void MatrixSetColumn( const Vector &in, int column, matrix3x4_t &out );
  473. inline void MatrixGetTranslation( const matrix3x4_t &in, Vector &out )
  474. {
  475. MatrixGetColumn ( in, 3, out );
  476. }
  477. inline void MatrixSetTranslation( const Vector &in, matrix3x4_t &out )
  478. {
  479. MatrixSetColumn ( in, 3, out );
  480. }
  481. void MatrixScaleBy ( const float flScale, matrix3x4_t &out );
  482. void MatrixScaleByZero ( matrix3x4_t &out );
  483. //void DecomposeRotation( const matrix3x4_t &mat, float *out );
  484. void ConcatRotations (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out);
  485. void ConcatTransforms (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out);
  486. // For identical interface w/ VMatrix
  487. inline void MatrixMultiply ( const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out )
  488. {
  489. ConcatTransforms( in1, in2, out );
  490. }
  491. void QuaternionSlerp( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  492. void QuaternionSlerpNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  493. void QuaternionBlend( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  494. void QuaternionBlendNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  495. void QuaternionIdentityBlend( const Quaternion &p, float t, Quaternion &qt );
  496. float QuaternionAngleDiff( const Quaternion &p, const Quaternion &q );
  497. void QuaternionScale( const Quaternion &p, float t, Quaternion &q );
  498. void QuaternionAlign( const Quaternion &p, const Quaternion &q, Quaternion &qt );
  499. float QuaternionDotProduct( const Quaternion &p, const Quaternion &q );
  500. void QuaternionConjugate( const Quaternion &p, Quaternion &q );
  501. void QuaternionInvert( const Quaternion &p, Quaternion &q );
  502. float QuaternionNormalize( Quaternion &q );
  503. void QuaternionAdd( const Quaternion &p, const Quaternion &q, Quaternion &qt );
  504. void QuaternionMult( const Quaternion &p, const Quaternion &q, Quaternion &qt );
  505. void QuaternionMatrix( const Quaternion &q, matrix3x4_t &matrix );
  506. void QuaternionMatrix( const Quaternion &q, const Vector &pos, matrix3x4_t &matrix );
  507. void QuaternionAngles( const Quaternion &q, QAngle &angles );
  508. void AngleQuaternion( const QAngle& angles, Quaternion &qt );
  509. void QuaternionAngles( const Quaternion &q, RadianEuler &angles );
  510. void AngleQuaternion( RadianEuler const &angles, Quaternion &qt );
  511. void QuaternionAxisAngle( const Quaternion &q, Vector &axis, float &angle );
  512. void AxisAngleQuaternion( const Vector &axis, float angle, Quaternion &q );
  513. void BasisToQuaternion( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Quaternion &q );
  514. void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q );
  515. // A couple methods to find the dot product of a vector with a matrix row or column...
  516. inline float MatrixRowDotProduct( const matrix3x4_t &in1, int row, const Vector& in2 )
  517. {
  518. Assert( (row >= 0) && (row < 3) );
  519. return DotProduct( in1[row], in2.Base() );
  520. }
  521. inline float MatrixColumnDotProduct( const matrix3x4_t &in1, int col, const Vector& in2 )
  522. {
  523. Assert( (col >= 0) && (col < 4) );
  524. return in1[0][col] * in2[0] + in1[1][col] * in2[1] + in1[2][col] * in2[2];
  525. }
  526. int __cdecl BoxOnPlaneSide (const float *emins, const float *emaxs, const cplane_t *plane);
  527. inline float anglemod(float a)
  528. {
  529. a = (360.f/65536) * ((int)(a*(65536.f/360.0f)) & 65535);
  530. return a;
  531. }
  532. // Remap a value in the range [A,B] to [C,D].
  533. inline float RemapVal( float val, float A, float B, float C, float D)
  534. {
  535. if ( A == B )
  536. return val >= B ? D : C;
  537. return C + (D - C) * (val - A) / (B - A);
  538. }
  539. inline float RemapValClamped( float val, float A, float B, float C, float D)
  540. {
  541. if ( A == B )
  542. return val >= B ? D : C;
  543. float cVal = (val - A) / (B - A);
  544. cVal = clamp( cVal, 0.0f, 1.0f );
  545. return C + (D - C) * cVal;
  546. }
  547. // Returns A + (B-A)*flPercent.
  548. // float Lerp( float flPercent, float A, float B );
  549. template <class T>
  550. FORCEINLINE T Lerp( float flPercent, T const &A, T const &B )
  551. {
  552. return A + (B - A) * flPercent;
  553. }
  554. FORCEINLINE float Sqr( float f )
  555. {
  556. return f*f;
  557. }
  558. // 5-argument floating point linear interpolation.
  559. // FLerp(f1,f2,i1,i2,x)=
  560. // f1 at x=i1
  561. // f2 at x=i2
  562. // smooth lerp between f1 and f2 at x>i1 and x<i2
  563. // extrapolation for x<i1 or x>i2
  564. //
  565. // If you know a function f(x)'s value (f1) at position i1, and its value (f2) at position i2,
  566. // the function can be linearly interpolated with FLerp(f1,f2,i1,i2,x)
  567. // i2=i1 will cause a divide by zero.
  568. static inline float FLerp(float f1, float f2, float i1, float i2, float x)
  569. {
  570. return f1+(f2-f1)*(x-i1)/(i2-i1);
  571. }
  572. #ifndef VECTOR_NO_SLOW_OPERATIONS
  573. // YWB: Specialization for interpolating euler angles via quaternions...
  574. template<> FORCEINLINE QAngle Lerp<QAngle>( float flPercent, const QAngle& q1, const QAngle& q2 )
  575. {
  576. // Avoid precision errors
  577. if ( q1 == q2 )
  578. return q1;
  579. Quaternion src, dest;
  580. // Convert to quaternions
  581. AngleQuaternion( q1, src );
  582. AngleQuaternion( q2, dest );
  583. Quaternion result;
  584. // Slerp
  585. QuaternionSlerp( src, dest, flPercent, result );
  586. // Convert to euler
  587. QAngle output;
  588. QuaternionAngles( result, output );
  589. return output;
  590. }
  591. #else
  592. #pragma error
  593. // NOTE NOTE: I haven't tested this!! It may not work! Check out interpolatedvar.cpp in the client dll to try it
  594. template<> FORCEINLINE QAngleByValue Lerp<QAngleByValue>( float flPercent, const QAngleByValue& q1, const QAngleByValue& q2 )
  595. {
  596. // Avoid precision errors
  597. if ( q1 == q2 )
  598. return q1;
  599. Quaternion src, dest;
  600. // Convert to quaternions
  601. AngleQuaternion( q1, src );
  602. AngleQuaternion( q2, dest );
  603. Quaternion result;
  604. // Slerp
  605. QuaternionSlerp( src, dest, flPercent, result );
  606. // Convert to euler
  607. QAngleByValue output;
  608. QuaternionAngles( result, output );
  609. return output;
  610. }
  611. #endif // VECTOR_NO_SLOW_OPERATIONS
  612. /// Same as swap(), but won't cause problems with std::swap
  613. template <class T>
  614. FORCEINLINE void V_swap( T& x, T& y )
  615. {
  616. T temp = x;
  617. x = y;
  618. y = temp;
  619. }
  620. template <class T> FORCEINLINE T AVG(T a, T b)
  621. {
  622. return (a+b)/2;
  623. }
  624. // number of elements in an array of static size
  625. #define NELEMS(x) ARRAYSIZE(x)
  626. // XYZ macro, for printf type functions - ex printf("%f %f %f",XYZ(myvector));
  627. #define XYZ(v) (v).x,(v).y,(v).z
  628. inline float Sign( float x )
  629. {
  630. return (x <0.0f) ? -1.0f : 1.0f;
  631. }
  632. //
  633. // Clamps the input integer to the given array bounds.
  634. // Equivalent to the following, but without using any branches:
  635. //
  636. // if( n < 0 ) return 0;
  637. // else if ( n > maxindex ) return maxindex;
  638. // else return n;
  639. //
  640. // This is not always a clear performance win, but when you have situations where a clamped
  641. // value is thrashing against a boundary this is a big win. (ie, valid, invalid, valid, invalid, ...)
  642. //
  643. // Note: This code has been run against all possible integers.
  644. //
  645. inline int ClampArrayBounds( int n, unsigned maxindex )
  646. {
  647. // mask is 0 if less than 4096, 0xFFFFFFFF if greater than
  648. unsigned int inrangemask = 0xFFFFFFFF + (((unsigned) n) > maxindex );
  649. unsigned int lessthan0mask = 0xFFFFFFFF + ( n >= 0 );
  650. // If the result was valid, set the result, (otherwise sets zero)
  651. int result = (inrangemask & n);
  652. // if the result was out of range or zero.
  653. result |= ((~inrangemask) & (~lessthan0mask)) & maxindex;
  654. return result;
  655. }
  656. #define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
  657. (((p)->type < 3)? \
  658. ( \
  659. ((p)->dist <= (emins)[(p)->type])? \
  660. 1 \
  661. : \
  662. ( \
  663. ((p)->dist >= (emaxs)[(p)->type])?\
  664. 2 \
  665. : \
  666. 3 \
  667. ) \
  668. ) \
  669. : \
  670. BoxOnPlaneSide( (emins), (emaxs), (p)))
  671. //-----------------------------------------------------------------------------
  672. // FIXME: Vector versions.... the float versions will go away hopefully soon!
  673. //-----------------------------------------------------------------------------
  674. void AngleVectors (const QAngle& angles, Vector *forward);
  675. void AngleVectors (const QAngle& angles, Vector *forward, Vector *right, Vector *up);
  676. void AngleVectorsTranspose (const QAngle& angles, Vector *forward, Vector *right, Vector *up);
  677. void AngleMatrix (const QAngle &angles, matrix3x4_t &mat );
  678. void AngleMatrix( const QAngle &angles, const Vector &position, matrix3x4_t &mat );
  679. void AngleMatrix (const RadianEuler &angles, matrix3x4_t &mat );
  680. void AngleMatrix( RadianEuler const &angles, const Vector &position, matrix3x4_t &mat );
  681. void AngleIMatrix (const QAngle &angles, matrix3x4_t &mat );
  682. void AngleIMatrix (const QAngle &angles, const Vector &position, matrix3x4_t &mat );
  683. void AngleIMatrix (const RadianEuler &angles, matrix3x4_t &mat );
  684. void VectorAngles( const Vector &forward, QAngle &angles );
  685. void VectorAngles( const Vector &forward, const Vector &pseudoup, QAngle &angles );
  686. void VectorMatrix( const Vector &forward, matrix3x4_t &mat );
  687. void VectorVectors( const Vector &forward, Vector &right, Vector &up );
  688. void SetIdentityMatrix( matrix3x4_t &mat );
  689. void SetScaleMatrix( float x, float y, float z, matrix3x4_t &dst );
  690. void MatrixBuildRotationAboutAxis( const Vector &vAxisOfRot, float angleDegrees, matrix3x4_t &dst );
  691. inline void SetScaleMatrix( float flScale, matrix3x4_t &dst )
  692. {
  693. SetScaleMatrix( flScale, flScale, flScale, dst );
  694. }
  695. inline void SetScaleMatrix( const Vector& scale, matrix3x4_t &dst )
  696. {
  697. SetScaleMatrix( scale.x, scale.y, scale.z, dst );
  698. }
  699. // Computes the inverse transpose
  700. void MatrixTranspose( matrix3x4_t& mat );
  701. void MatrixTranspose( const matrix3x4_t& src, matrix3x4_t& dst );
  702. void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst );
  703. inline void PositionMatrix( const Vector &position, matrix3x4_t &mat )
  704. {
  705. MatrixSetColumn( position, 3, mat );
  706. }
  707. inline void MatrixPosition( const matrix3x4_t &matrix, Vector &position )
  708. {
  709. MatrixGetColumn( matrix, 3, position );
  710. }
  711. inline void VectorRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out)
  712. {
  713. VectorRotate( &in1.x, in2, &out.x );
  714. }
  715. inline void VectorIRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out)
  716. {
  717. VectorIRotate( &in1.x, in2, &out.x );
  718. }
  719. inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles )
  720. {
  721. MatrixAngles( matrix, &angles.x );
  722. }
  723. inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles, Vector &position )
  724. {
  725. MatrixAngles( matrix, angles );
  726. MatrixPosition( matrix, position );
  727. }
  728. inline void MatrixAngles( const matrix3x4_t &matrix, RadianEuler &angles )
  729. {
  730. MatrixAngles( matrix, &angles.x );
  731. angles.Init( DEG2RAD( angles.z ), DEG2RAD( angles.x ), DEG2RAD( angles.y ) );
  732. }
  733. void MatrixAngles( const matrix3x4_t &mat, RadianEuler &angles, Vector &position );
  734. void MatrixAngles( const matrix3x4_t &mat, Quaternion &q, Vector &position );
  735. inline int VectorCompare (const Vector& v1, const Vector& v2)
  736. {
  737. return v1 == v2;
  738. }
  739. inline void VectorTransform (const Vector& in1, const matrix3x4_t &in2, Vector &out)
  740. {
  741. VectorTransform( &in1.x, in2, &out.x );
  742. }
  743. inline void VectorITransform (const Vector& in1, const matrix3x4_t &in2, Vector &out)
  744. {
  745. VectorITransform( &in1.x, in2, &out.x );
  746. }
  747. /*
  748. inline void DecomposeRotation( const matrix3x4_t &mat, Vector &out )
  749. {
  750. DecomposeRotation( mat, &out.x );
  751. }
  752. */
  753. inline int BoxOnPlaneSide (const Vector& emins, const Vector& emaxs, const cplane_t *plane )
  754. {
  755. return BoxOnPlaneSide( &emins.x, &emaxs.x, plane );
  756. }
  757. inline void VectorFill(Vector& a, float b)
  758. {
  759. a[0]=a[1]=a[2]=b;
  760. }
  761. inline void VectorNegate(Vector& a)
  762. {
  763. a[0] = -a[0];
  764. a[1] = -a[1];
  765. a[2] = -a[2];
  766. }
  767. inline vec_t VectorAvg(Vector& a)
  768. {
  769. return ( a[0] + a[1] + a[2] ) / 3;
  770. }
  771. //-----------------------------------------------------------------------------
  772. // Box/plane test (slow version)
  773. //-----------------------------------------------------------------------------
  774. inline int FASTCALL BoxOnPlaneSide2 (const Vector& emins, const Vector& emaxs, const cplane_t *p, float tolerance = 0.f )
  775. {
  776. Vector corners[2];
  777. if (p->normal[0] < 0)
  778. {
  779. corners[0][0] = emins[0];
  780. corners[1][0] = emaxs[0];
  781. }
  782. else
  783. {
  784. corners[1][0] = emins[0];
  785. corners[0][0] = emaxs[0];
  786. }
  787. if (p->normal[1] < 0)
  788. {
  789. corners[0][1] = emins[1];
  790. corners[1][1] = emaxs[1];
  791. }
  792. else
  793. {
  794. corners[1][1] = emins[1];
  795. corners[0][1] = emaxs[1];
  796. }
  797. if (p->normal[2] < 0)
  798. {
  799. corners[0][2] = emins[2];
  800. corners[1][2] = emaxs[2];
  801. }
  802. else
  803. {
  804. corners[1][2] = emins[2];
  805. corners[0][2] = emaxs[2];
  806. }
  807. int sides = 0;
  808. float dist1 = DotProduct (p->normal, corners[0]) - p->dist;
  809. if (dist1 >= tolerance)
  810. sides = 1;
  811. float dist2 = DotProduct (p->normal, corners[1]) - p->dist;
  812. if (dist2 < -tolerance)
  813. sides |= 2;
  814. return sides;
  815. }
  816. //-----------------------------------------------------------------------------
  817. // Helpers for bounding box construction
  818. //-----------------------------------------------------------------------------
  819. void ClearBounds (Vector& mins, Vector& maxs);
  820. void AddPointToBounds (const Vector& v, Vector& mins, Vector& maxs);
  821. //
  822. // COLORSPACE/GAMMA CONVERSION STUFF
  823. //
  824. void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright );
  825. // convert texture to linear 0..1 value
  826. inline float TexLightToLinear( int c, int exponent )
  827. {
  828. extern float power2_n[256];
  829. Assert( exponent >= -128 && exponent <= 127 );
  830. return ( float )c * power2_n[exponent+128];
  831. }
  832. // convert texture to linear 0..1 value
  833. int LinearToTexture( float f );
  834. // converts 0..1 linear value to screen gamma (0..255)
  835. int LinearToScreenGamma( float f );
  836. float TextureToLinear( int c );
  837. // compressed color format
  838. struct ColorRGBExp32
  839. {
  840. byte r, g, b;
  841. signed char exponent;
  842. };
  843. void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out );
  844. void VectorToColorRGBExp32( const Vector& v, ColorRGBExp32 &c );
  845. // solve for "x" where "a x^2 + b x + c = 0", return true if solution exists
  846. bool SolveQuadratic( float a, float b, float c, float &root1, float &root2 );
  847. // solves for "a, b, c" where "a x^2 + b x + c = y", return true if solution exists
  848. bool SolveInverseQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c );
  849. // solves for a,b,c specified as above, except that it always creates a monotonically increasing or
  850. // decreasing curve if the data is monotonically increasing or decreasing. In order to enforce the
  851. // monoticity condition, it is possible that the resulting quadratic will only approximate the data
  852. // instead of interpolating it. This code is not especially fast.
  853. bool SolveInverseQuadraticMonotonic( float x1, float y1, float x2, float y2,
  854. float x3, float y3, float &a, float &b, float &c );
  855. // solves for "a, b, c" where "1/(a x^2 + b x + c ) = y", return true if solution exists
  856. bool SolveInverseReciprocalQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c );
  857. // rotate a vector around the Z axis (YAW)
  858. void VectorYawRotate( const Vector& in, float flYaw, Vector &out);
  859. // Bias takes an X value between 0 and 1 and returns another value between 0 and 1
  860. // The curve is biased towards 0 or 1 based on biasAmt, which is between 0 and 1.
  861. // Lower values of biasAmt bias the curve towards 0 and higher values bias it towards 1.
  862. //
  863. // For example, with biasAmt = 0.2, the curve looks like this:
  864. //
  865. // 1
  866. // | *
  867. // | *
  868. // | *
  869. // | **
  870. // | **
  871. // | ****
  872. // |*********
  873. // |___________________
  874. // 0 1
  875. //
  876. //
  877. // With biasAmt = 0.8, the curve looks like this:
  878. //
  879. // 1
  880. // | **************
  881. // | **
  882. // | *
  883. // | *
  884. // |*
  885. // |*
  886. // |*
  887. // |___________________
  888. // 0 1
  889. //
  890. // With a biasAmt of 0.5, Bias returns X.
  891. float Bias( float x, float biasAmt );
  892. // Gain is similar to Bias, but biasAmt biases towards or away from 0.5.
  893. // Lower bias values bias towards 0.5 and higher bias values bias away from it.
  894. //
  895. // For example, with biasAmt = 0.2, the curve looks like this:
  896. //
  897. // 1
  898. // | *
  899. // | *
  900. // | **
  901. // | ***************
  902. // | **
  903. // | *
  904. // |*
  905. // |___________________
  906. // 0 1
  907. //
  908. //
  909. // With biasAmt = 0.8, the curve looks like this:
  910. //
  911. // 1
  912. // | *****
  913. // | ***
  914. // | *
  915. // | *
  916. // | *
  917. // | ***
  918. // |*****
  919. // |___________________
  920. // 0 1
  921. float Gain( float x, float biasAmt );
  922. // SmoothCurve maps a 0-1 value into another 0-1 value based on a cosine wave
  923. // where the derivatives of the function at 0 and 1 (and 0.5) are 0. This is useful for
  924. // any fadein/fadeout effect where it should start and end smoothly.
  925. //
  926. // The curve looks like this:
  927. //
  928. // 1
  929. // | **
  930. // | * *
  931. // | * *
  932. // | * *
  933. // | * *
  934. // | ** **
  935. // |*** ***
  936. // |___________________
  937. // 0 1
  938. //
  939. float SmoothCurve( float x );
  940. // This works like SmoothCurve, with two changes:
  941. //
  942. // 1. Instead of the curve peaking at 0.5, it will peak at flPeakPos.
  943. // (So if you specify flPeakPos=0.2, then the peak will slide to the left).
  944. //
  945. // 2. flPeakSharpness is a 0-1 value controlling the sharpness of the peak.
  946. // Low values blunt the peak and high values sharpen the peak.
  947. float SmoothCurve_Tweak( float x, float flPeakPos=0.5, float flPeakSharpness=0.5 );
  948. //float ExponentialDecay( float halflife, float dt );
  949. //float ExponentialDecay( float decayTo, float decayTime, float dt );
  950. // halflife is time for value to reach 50%
  951. inline float ExponentialDecay( float halflife, float dt )
  952. {
  953. // log(0.5) == -0.69314718055994530941723212145818
  954. return expf( -0.69314718f / halflife * dt);
  955. }
  956. // decayTo is factor the value should decay to in decayTime
  957. inline float ExponentialDecay( float decayTo, float decayTime, float dt )
  958. {
  959. return expf( logf( decayTo ) / decayTime * dt);
  960. }
  961. // Get the integrated distanced traveled
  962. // decayTo is factor the value should decay to in decayTime
  963. // dt is the time relative to the last velocity update
  964. inline float ExponentialDecayIntegral( float decayTo, float decayTime, float dt )
  965. {
  966. return (powf( decayTo, dt / decayTime) * decayTime - decayTime) / logf( decayTo );
  967. }
  968. // hermite basis function for smooth interpolation
  969. // Similar to Gain() above, but very cheap to call
  970. // value should be between 0 & 1 inclusive
  971. inline float SimpleSpline( float value )
  972. {
  973. float valueSquared = value * value;
  974. // Nice little ease-in, ease-out spline-like curve
  975. return (3 * valueSquared - 2 * valueSquared * value);
  976. }
  977. // remaps a value in [startInterval, startInterval+rangeInterval] from linear to
  978. // spline using SimpleSpline
  979. inline float SimpleSplineRemapVal( float val, float A, float B, float C, float D)
  980. {
  981. if ( A == B )
  982. return val >= B ? D : C;
  983. float cVal = (val - A) / (B - A);
  984. return C + (D - C) * SimpleSpline( cVal );
  985. }
  986. // remaps a value in [startInterval, startInterval+rangeInterval] from linear to
  987. // spline using SimpleSpline
  988. inline float SimpleSplineRemapValClamped( float val, float A, float B, float C, float D )
  989. {
  990. if ( A == B )
  991. return val >= B ? D : C;
  992. float cVal = (val - A) / (B - A);
  993. cVal = clamp( cVal, 0.0f, 1.0f );
  994. return C + (D - C) * SimpleSpline( cVal );
  995. }
  996. FORCEINLINE int RoundFloatToInt(float f)
  997. {
  998. #if defined(__i386__) || defined(_M_IX86) || defined( PLATFORM_WINDOWS_PC64 ) || defined(__x86_64__)
  999. return _mm_cvtss_si32(_mm_load_ss(&f));
  1000. #elif defined( _X360 )
  1001. #ifdef Assert
  1002. Assert( IsFPUControlWordSet() );
  1003. #endif
  1004. union
  1005. {
  1006. double flResult;
  1007. int pResult[2];
  1008. };
  1009. flResult = __fctiw( f );
  1010. return pResult[1];
  1011. #else
  1012. #error Unknown architecture
  1013. #endif
  1014. }
  1015. FORCEINLINE unsigned char RoundFloatToByte(float f)
  1016. {
  1017. int nResult = RoundFloatToInt(f);
  1018. #ifdef Assert
  1019. Assert( (nResult & ~0xFF) == 0 );
  1020. #endif
  1021. return (unsigned char) nResult;
  1022. }
  1023. FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f)
  1024. {
  1025. #if defined( _X360 )
  1026. #ifdef Assert
  1027. Assert( IsFPUControlWordSet() );
  1028. #endif
  1029. union
  1030. {
  1031. double flResult;
  1032. int pIntResult[2];
  1033. unsigned long pResult[2];
  1034. };
  1035. flResult = __fctiw( f );
  1036. Assert( pIntResult[1] >= 0 );
  1037. return pResult[1];
  1038. #else // !X360
  1039. #if defined( PLATFORM_WINDOWS_PC64 )
  1040. uint nRet = ( uint ) f;
  1041. if ( nRet & 1 )
  1042. {
  1043. if ( ( f - floor( f ) >= 0.5 ) )
  1044. {
  1045. nRet++;
  1046. }
  1047. }
  1048. else
  1049. {
  1050. if ( ( f - floor( f ) > 0.5 ) )
  1051. {
  1052. nRet++;
  1053. }
  1054. }
  1055. return nRet;
  1056. #else // PLATFORM_WINDOWS_PC64
  1057. unsigned char nResult[8];
  1058. #if defined( _WIN32 )
  1059. __asm
  1060. {
  1061. fld f
  1062. fistp qword ptr nResult
  1063. }
  1064. #elif POSIX
  1065. __asm __volatile__ (
  1066. "fistpl %0;": "=m" (nResult): "t" (f) : "st"
  1067. );
  1068. #endif
  1069. return *((unsigned long*)nResult);
  1070. #endif // PLATFORM_WINDOWS_PC64
  1071. #endif // !X360
  1072. }
  1073. FORCEINLINE bool IsIntegralValue( float flValue, float flTolerance = 0.001f )
  1074. {
  1075. return fabs( RoundFloatToInt( flValue ) - flValue ) < flTolerance;
  1076. }
  1077. // Fast, accurate ftol:
  1078. FORCEINLINE int Float2Int( float a )
  1079. {
  1080. #if defined( _X360 )
  1081. union
  1082. {
  1083. double flResult;
  1084. int pResult[2];
  1085. };
  1086. flResult = __fctiwz( a );
  1087. return pResult[1];
  1088. #else // !X360
  1089. // Rely on compiler to generate CVTTSS2SI on x86
  1090. return (int) a;
  1091. #endif
  1092. }
  1093. // Over 15x faster than: (int)floor(value)
  1094. inline int Floor2Int( float a )
  1095. {
  1096. int RetVal;
  1097. #if defined( __i386__ )
  1098. // Convert to int and back, compare, subtract one if too big
  1099. __m128 a128 = _mm_set_ss(a);
  1100. RetVal = _mm_cvtss_si32(a128);
  1101. __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal);
  1102. RetVal -= _mm_comigt_ss( rounded128, a128 );
  1103. #else
  1104. RetVal = static_cast<int>( floor(a) );
  1105. #endif
  1106. return RetVal;
  1107. }
  1108. //-----------------------------------------------------------------------------
  1109. // Fast color conversion from float to unsigned char
  1110. //-----------------------------------------------------------------------------
  1111. FORCEINLINE unsigned int FastFToC( float c )
  1112. {
  1113. #if defined( __i386__ )
  1114. // IEEE float bit manipulation works for values between [0, 1<<23)
  1115. union { float f; int i; } convert = { c*255.0f + (float)(1<<23) };
  1116. return convert.i & 255;
  1117. #else
  1118. // consoles CPUs suffer from load-hit-store penalty
  1119. return Float2Int( c * 255.0f );
  1120. #endif
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // Fast conversion from float to integer with magnitude less than 2**22
  1124. //-----------------------------------------------------------------------------
  1125. FORCEINLINE int FastFloatToSmallInt( float c )
  1126. {
  1127. #if defined( __i386__ )
  1128. // IEEE float bit manipulation works for values between [-1<<22, 1<<22)
  1129. union { float f; int i; } convert = { c + (float)(3<<22) };
  1130. return (convert.i & ((1<<23)-1)) - (1<<22);
  1131. #else
  1132. // consoles CPUs suffer from load-hit-store penalty
  1133. return Float2Int( c );
  1134. #endif
  1135. }
  1136. //-----------------------------------------------------------------------------
  1137. // Purpose: Bound input float to .001 (millisecond) boundary
  1138. // Input : in -
  1139. // Output : inline float
  1140. //-----------------------------------------------------------------------------
  1141. inline float ClampToMsec( float in )
  1142. {
  1143. int msec = Floor2Int( in * 1000.0f + 0.5f );
  1144. return 0.001f * msec;
  1145. }
  1146. // Over 15x faster than: (int)ceil(value)
  1147. inline int Ceil2Int( float a )
  1148. {
  1149. int RetVal;
  1150. #if defined( __i386__ )
  1151. // Convert to int and back, compare, add one if too small
  1152. __m128 a128 = _mm_load_ss(&a);
  1153. RetVal = _mm_cvtss_si32(a128);
  1154. __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal);
  1155. RetVal += _mm_comilt_ss( rounded128, a128 );
  1156. #else
  1157. RetVal = static_cast<int>( ceil(a) );
  1158. #endif
  1159. return RetVal;
  1160. }
  1161. // Regular signed area of triangle
  1162. #define TriArea2D( A, B, C ) \
  1163. ( 0.5f * ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) )
  1164. // This version doesn't premultiply by 0.5f, so it's the area of the rectangle instead
  1165. #define TriArea2DTimesTwo( A, B, C ) \
  1166. ( ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) )
  1167. // Get the barycentric coordinates of "pt" in triangle [A,B,C].
  1168. inline void GetBarycentricCoords2D(
  1169. Vector2D const &A,
  1170. Vector2D const &B,
  1171. Vector2D const &C,
  1172. Vector2D const &pt,
  1173. float bcCoords[3] )
  1174. {
  1175. // Note, because to top and bottom are both x2, the issue washes out in the composite
  1176. float invTriArea = 1.0f / TriArea2DTimesTwo( A, B, C );
  1177. // NOTE: We assume here that the lightmap coordinate vertices go counterclockwise.
  1178. // If not, TriArea2D() is negated so this works out right.
  1179. bcCoords[0] = TriArea2DTimesTwo( B, C, pt ) * invTriArea;
  1180. bcCoords[1] = TriArea2DTimesTwo( C, A, pt ) * invTriArea;
  1181. bcCoords[2] = TriArea2DTimesTwo( A, B, pt ) * invTriArea;
  1182. }
  1183. // Return true of the sphere might touch the box (the sphere is actually treated
  1184. // like a box itself, so this may return true if the sphere's bounding box touches
  1185. // a corner of the box but the sphere itself doesn't).
  1186. inline bool QuickBoxSphereTest(
  1187. const Vector& vOrigin,
  1188. float flRadius,
  1189. const Vector& bbMin,
  1190. const Vector& bbMax )
  1191. {
  1192. return vOrigin.x - flRadius < bbMax.x && vOrigin.x + flRadius > bbMin.x &&
  1193. vOrigin.y - flRadius < bbMax.y && vOrigin.y + flRadius > bbMin.y &&
  1194. vOrigin.z - flRadius < bbMax.z && vOrigin.z + flRadius > bbMin.z;
  1195. }
  1196. // Return true of the boxes intersect (but not if they just touch).
  1197. inline bool QuickBoxIntersectTest(
  1198. const Vector& vBox1Min,
  1199. const Vector& vBox1Max,
  1200. const Vector& vBox2Min,
  1201. const Vector& vBox2Max )
  1202. {
  1203. return
  1204. vBox1Min.x < vBox2Max.x && vBox1Max.x > vBox2Min.x &&
  1205. vBox1Min.y < vBox2Max.y && vBox1Max.y > vBox2Min.y &&
  1206. vBox1Min.z < vBox2Max.z && vBox1Max.z > vBox2Min.z;
  1207. }
  1208. extern float GammaToLinearFullRange( float gamma );
  1209. extern float LinearToGammaFullRange( float linear );
  1210. extern float GammaToLinear( float gamma );
  1211. extern float LinearToGamma( float linear );
  1212. extern float SrgbGammaToLinear( float flSrgbGammaValue );
  1213. extern float SrgbLinearToGamma( float flLinearValue );
  1214. extern float X360GammaToLinear( float fl360GammaValue );
  1215. extern float X360LinearToGamma( float flLinearValue );
  1216. extern float SrgbGammaTo360Gamma( float flSrgbGammaValue );
  1217. // linear (0..4) to screen corrected vertex space (0..1?)
  1218. FORCEINLINE float LinearToVertexLight( float f )
  1219. {
  1220. extern float lineartovertex[4096];
  1221. // Gotta clamp before the multiply; could overflow...
  1222. // assume 0..4 range
  1223. int i = RoundFloatToInt( f * 1024.f );
  1224. // Presumably the comman case will be not to clamp, so check that first:
  1225. if( (unsigned)i > 4095 )
  1226. {
  1227. if ( i < 0 )
  1228. i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream
  1229. else
  1230. i = 4095;
  1231. }
  1232. return lineartovertex[i];
  1233. }
  1234. FORCEINLINE unsigned char LinearToLightmap( float f )
  1235. {
  1236. extern unsigned char lineartolightmap[4096];
  1237. // Gotta clamp before the multiply; could overflow...
  1238. int i = RoundFloatToInt( f * 1024.f ); // assume 0..4 range
  1239. // Presumably the comman case will be not to clamp, so check that first:
  1240. if ( (unsigned)i > 4095 )
  1241. {
  1242. if ( i < 0 )
  1243. i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream
  1244. else
  1245. i = 4095;
  1246. }
  1247. return lineartolightmap[i];
  1248. }
  1249. FORCEINLINE void ColorClamp( Vector& color )
  1250. {
  1251. float maxc = max( color.x, max( color.y, color.z ) );
  1252. if ( maxc > 1.0f )
  1253. {
  1254. float ooMax = 1.0f / maxc;
  1255. color.x *= ooMax;
  1256. color.y *= ooMax;
  1257. color.z *= ooMax;
  1258. }
  1259. if ( color[0] < 0.f ) color[0] = 0.f;
  1260. if ( color[1] < 0.f ) color[1] = 0.f;
  1261. if ( color[2] < 0.f ) color[2] = 0.f;
  1262. }
  1263. inline void ColorClampTruncate( Vector& color )
  1264. {
  1265. if (color[0] > 1.0f) color[0] = 1.0f; else if (color[0] < 0.0f) color[0] = 0.0f;
  1266. if (color[1] > 1.0f) color[1] = 1.0f; else if (color[1] < 0.0f) color[1] = 0.0f;
  1267. if (color[2] > 1.0f) color[2] = 1.0f; else if (color[2] < 0.0f) color[2] = 0.0f;
  1268. }
  1269. // Interpolate a Catmull-Rom spline.
  1270. // t is a [0,1] value and interpolates a curve between p2 and p3.
  1271. void Catmull_Rom_Spline(
  1272. const Vector &p1,
  1273. const Vector &p2,
  1274. const Vector &p3,
  1275. const Vector &p4,
  1276. float t,
  1277. Vector &output );
  1278. // Interpolate a Catmull-Rom spline.
  1279. // Returns the tangent of the point at t of the spline
  1280. void Catmull_Rom_Spline_Tangent(
  1281. const Vector &p1,
  1282. const Vector &p2,
  1283. const Vector &p3,
  1284. const Vector &p4,
  1285. float t,
  1286. Vector &output );
  1287. // area under the curve [0..t]
  1288. void Catmull_Rom_Spline_Integral(
  1289. const Vector &p1,
  1290. const Vector &p2,
  1291. const Vector &p3,
  1292. const Vector &p4,
  1293. float t,
  1294. Vector& output );
  1295. // area under the curve [0..1]
  1296. void Catmull_Rom_Spline_Integral(
  1297. const Vector &p1,
  1298. const Vector &p2,
  1299. const Vector &p3,
  1300. const Vector &p4,
  1301. Vector& output );
  1302. // Interpolate a Catmull-Rom spline.
  1303. // Normalize p2->p1 and p3->p4 to be the same length as p2->p3
  1304. void Catmull_Rom_Spline_Normalize(
  1305. const Vector &p1,
  1306. const Vector &p2,
  1307. const Vector &p3,
  1308. const Vector &p4,
  1309. float t,
  1310. Vector &output );
  1311. // area under the curve [0..t]
  1312. // Normalize p2->p1 and p3->p4 to be the same length as p2->p3
  1313. void Catmull_Rom_Spline_Integral_Normalize(
  1314. const Vector &p1,
  1315. const Vector &p2,
  1316. const Vector &p3,
  1317. const Vector &p4,
  1318. float t,
  1319. Vector& output );
  1320. // Interpolate a Catmull-Rom spline.
  1321. // Normalize p2.x->p1.x and p3.x->p4.x to be the same length as p2.x->p3.x
  1322. void Catmull_Rom_Spline_NormalizeX(
  1323. const Vector &p1,
  1324. const Vector &p2,
  1325. const Vector &p3,
  1326. const Vector &p4,
  1327. float t,
  1328. Vector &output );
  1329. // area under the curve [0..t]
  1330. void Catmull_Rom_Spline_NormalizeX(
  1331. const Vector &p1,
  1332. const Vector &p2,
  1333. const Vector &p3,
  1334. const Vector &p4,
  1335. float t,
  1336. Vector& output );
  1337. // Interpolate a Hermite spline.
  1338. // t is a [0,1] value and interpolates a curve between p1 and p2 with the deltas d1 and d2.
  1339. void Hermite_Spline(
  1340. const Vector &p1,
  1341. const Vector &p2,
  1342. const Vector &d1,
  1343. const Vector &d2,
  1344. float t,
  1345. Vector& output );
  1346. float Hermite_Spline(
  1347. float p1,
  1348. float p2,
  1349. float d1,
  1350. float d2,
  1351. float t );
  1352. // t is a [0,1] value and interpolates a curve between p1 and p2 with the slopes p0->p1 and p1->p2
  1353. void Hermite_Spline(
  1354. const Vector &p0,
  1355. const Vector &p1,
  1356. const Vector &p2,
  1357. float t,
  1358. Vector& output );
  1359. float Hermite_Spline(
  1360. float p0,
  1361. float p1,
  1362. float p2,
  1363. float t );
  1364. void Hermite_SplineBasis( float t, float basis[] );
  1365. void Hermite_Spline(
  1366. const Quaternion &q0,
  1367. const Quaternion &q1,
  1368. const Quaternion &q2,
  1369. float t,
  1370. Quaternion &output );
  1371. // See http://en.wikipedia.org/wiki/Kochanek-Bartels_curves
  1372. //
  1373. // Tension: -1 = Round -> 1 = Tight
  1374. // Bias: -1 = Pre-shoot (bias left) -> 1 = Post-shoot (bias right)
  1375. // Continuity: -1 = Box corners -> 1 = Inverted corners
  1376. //
  1377. // If T=B=C=0 it's the same matrix as Catmull-Rom.
  1378. // If T=1 & B=C=0 it's the same as Cubic.
  1379. // If T=B=0 & C=-1 it's just linear interpolation
  1380. //
  1381. // See http://news.povray.org/povray.binaries.tutorials/attachment/%[email protected]%3E/Splines.bas.txt
  1382. // for example code and descriptions of various spline types...
  1383. //
  1384. void Kochanek_Bartels_Spline(
  1385. float tension,
  1386. float bias,
  1387. float continuity,
  1388. const Vector &p1,
  1389. const Vector &p2,
  1390. const Vector &p3,
  1391. const Vector &p4,
  1392. float t,
  1393. Vector& output );
  1394. void Kochanek_Bartels_Spline_NormalizeX(
  1395. float tension,
  1396. float bias,
  1397. float continuity,
  1398. const Vector &p1,
  1399. const Vector &p2,
  1400. const Vector &p3,
  1401. const Vector &p4,
  1402. float t,
  1403. Vector& output );
  1404. // See link at Kochanek_Bartels_Spline for info on the basis matrix used
  1405. void Cubic_Spline(
  1406. const Vector &p1,
  1407. const Vector &p2,
  1408. const Vector &p3,
  1409. const Vector &p4,
  1410. float t,
  1411. Vector& output );
  1412. void Cubic_Spline_NormalizeX(
  1413. const Vector &p1,
  1414. const Vector &p2,
  1415. const Vector &p3,
  1416. const Vector &p4,
  1417. float t,
  1418. Vector& output );
  1419. // See link at Kochanek_Bartels_Spline for info on the basis matrix used
  1420. void BSpline(
  1421. const Vector &p1,
  1422. const Vector &p2,
  1423. const Vector &p3,
  1424. const Vector &p4,
  1425. float t,
  1426. Vector& output );
  1427. void BSpline_NormalizeX(
  1428. const Vector &p1,
  1429. const Vector &p2,
  1430. const Vector &p3,
  1431. const Vector &p4,
  1432. float t,
  1433. Vector& output );
  1434. // See link at Kochanek_Bartels_Spline for info on the basis matrix used
  1435. void Parabolic_Spline(
  1436. const Vector &p1,
  1437. const Vector &p2,
  1438. const Vector &p3,
  1439. const Vector &p4,
  1440. float t,
  1441. Vector& output );
  1442. void Parabolic_Spline_NormalizeX(
  1443. const Vector &p1,
  1444. const Vector &p2,
  1445. const Vector &p3,
  1446. const Vector &p4,
  1447. float t,
  1448. Vector& output );
  1449. // quintic interpolating polynomial from Perlin.
  1450. // 0->0, 1->1, smooth-in between with smooth tangents
  1451. FORCEINLINE float QuinticInterpolatingPolynomial(float t)
  1452. {
  1453. // 6t^5-15t^4+10t^3
  1454. return t * t * t *( t * ( t* 6.0 - 15.0 ) + 10.0 );
  1455. }
  1456. // given a table of sorted tabulated positions, return the two indices and blendfactor to linear
  1457. // interpolate. Does a search. Can be used to find the blend value to interpolate between
  1458. // keyframes.
  1459. void GetInterpolationData( float const *pKnotPositions,
  1460. float const *pKnotValues,
  1461. int nNumValuesinList,
  1462. int nInterpolationRange,
  1463. float flPositionToInterpolateAt,
  1464. bool bWrap,
  1465. float *pValueA,
  1466. float *pValueB,
  1467. float *pInterpolationValue);
  1468. float RangeCompressor( float flValue, float flMin, float flMax, float flBase );
  1469. // Get the minimum distance from vOrigin to the bounding box defined by [mins,maxs]
  1470. // using voronoi regions.
  1471. // 0 is returned if the origin is inside the box.
  1472. float CalcSqrDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point );
  1473. void CalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut );
  1474. void CalcSqrDistAndClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut, float &distSqrOut );
  1475. inline float CalcDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point )
  1476. {
  1477. float flDistSqr = CalcSqrDistanceToAABB( mins, maxs, point );
  1478. return sqrt(flDistSqr);
  1479. }
  1480. // Get the closest point from P to the (infinite) line through vLineA and vLineB and
  1481. // calculate the shortest distance from P to the line.
  1482. // If you pass in a value for t, it will tell you the t for (A + (B-A)t) to get the closest point.
  1483. // If the closest point lies on the segment between A and B, then 0 <= t <= 1.
  1484. void CalcClosestPointOnLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 );
  1485. float CalcDistanceToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1486. float CalcDistanceSqrToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1487. // The same three functions as above, except now the line is closed between A and B.
  1488. void CalcClosestPointOnLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 );
  1489. float CalcDistanceToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1490. float CalcDistanceSqrToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1491. // A function to compute the closes line segment connnection two lines (or false if the lines are parallel, etc.)
  1492. bool CalcLineToLineIntersectionSegment(
  1493. const Vector& p1,const Vector& p2,const Vector& p3,const Vector& p4,Vector *s1,Vector *s2,
  1494. float *t1, float *t2 );
  1495. // The above functions in 2D
  1496. void CalcClosestPointOnLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 );
  1497. float CalcDistanceToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1498. float CalcDistanceSqrToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1499. void CalcClosestPointOnLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 );
  1500. float CalcDistanceToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1501. float CalcDistanceSqrToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1502. // Init the mathlib
  1503. void MathLib_Init( float gamma = 2.2f, float texGamma = 2.2f, float brightness = 0.0f, int overbright = 2.0f, bool bAllow3DNow = true, bool bAllowSSE = true, bool bAllowSSE2 = true, bool bAllowMMX = true );
  1504. bool MathLib_3DNowEnabled( void );
  1505. bool MathLib_MMXEnabled( void );
  1506. bool MathLib_SSEEnabled( void );
  1507. bool MathLib_SSE2Enabled( void );
  1508. float Approach( float target, float value, float speed );
  1509. float ApproachAngle( float target, float value, float speed );
  1510. float AngleDiff( float destAngle, float srcAngle );
  1511. float AngleDistance( float next, float cur );
  1512. float AngleNormalize( float angle );
  1513. // ensure that 0 <= angle <= 360
  1514. float AngleNormalizePositive( float angle );
  1515. bool AnglesAreEqual( float a, float b, float tolerance = 0.0f );
  1516. void RotationDeltaAxisAngle( const QAngle &srcAngles, const QAngle &destAngles, Vector &deltaAxis, float &deltaAngle );
  1517. void RotationDelta( const QAngle &srcAngles, const QAngle &destAngles, QAngle *out );
  1518. void ComputeTrianglePlane( const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept );
  1519. int PolyFromPlane( Vector *outVerts, const Vector& normal, float dist, float fHalfScale = 9000.0f );
  1520. int ClipPolyToPlane( Vector *inVerts, int vertCount, Vector *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon = 0.1f );
  1521. int ClipPolyToPlane_Precise( double *inVerts, int vertCount, double *outVerts, const double *normal, double dist, double fOnPlaneEpsilon = 0.1 );
  1522. //-----------------------------------------------------------------------------
  1523. // Computes a reasonable tangent space for a triangle
  1524. //-----------------------------------------------------------------------------
  1525. void CalcTriangleTangentSpace( const Vector &p0, const Vector &p1, const Vector &p2,
  1526. const Vector2D &t0, const Vector2D &t1, const Vector2D& t2,
  1527. Vector &sVect, Vector &tVect );
  1528. //-----------------------------------------------------------------------------
  1529. // Transforms a AABB into another space; which will inherently grow the box.
  1530. //-----------------------------------------------------------------------------
  1531. void TransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  1532. //-----------------------------------------------------------------------------
  1533. // Uses the inverse transform of in1
  1534. //-----------------------------------------------------------------------------
  1535. void ITransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  1536. //-----------------------------------------------------------------------------
  1537. // Rotates a AABB into another space; which will inherently grow the box.
  1538. // (same as TransformAABB, but doesn't take the translation into account)
  1539. //-----------------------------------------------------------------------------
  1540. void RotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  1541. //-----------------------------------------------------------------------------
  1542. // Uses the inverse transform of in1
  1543. //-----------------------------------------------------------------------------
  1544. void IRotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  1545. //-----------------------------------------------------------------------------
  1546. // Transform a plane
  1547. //-----------------------------------------------------------------------------
  1548. inline void MatrixTransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane )
  1549. {
  1550. // What we want to do is the following:
  1551. // 1) transform the normal into the new space.
  1552. // 2) Determine a point on the old plane given by plane dist * plane normal
  1553. // 3) Transform that point into the new space
  1554. // 4) Plane dist = DotProduct( new normal, new point )
  1555. // An optimized version, which works if the plane is orthogonal.
  1556. // 1) Transform the normal into the new space
  1557. // 2) Realize that transforming the old plane point into the new space
  1558. // is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ]
  1559. // where d = old plane dist, n' = transformed normal, Tn = translational component of transform
  1560. // 3) Compute the new plane dist using the dot product of the normal result of #2
  1561. // For a correct result, this should be an inverse-transpose matrix
  1562. // but that only matters if there are nonuniform scale or skew factors in this matrix.
  1563. VectorRotate( inPlane.normal, src, outPlane.normal );
  1564. outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
  1565. outPlane.dist += outPlane.normal.x * src[0][3] + outPlane.normal.y * src[1][3] + outPlane.normal.z * src[2][3];
  1566. }
  1567. inline void MatrixITransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane )
  1568. {
  1569. // The trick here is that Tn = translational component of transform,
  1570. // but for an inverse transform, Tn = - R^-1 * T
  1571. Vector vecTranslation;
  1572. MatrixGetColumn( src, 3, vecTranslation );
  1573. Vector vecInvTranslation;
  1574. VectorIRotate( vecTranslation, src, vecInvTranslation );
  1575. VectorIRotate( inPlane.normal, src, outPlane.normal );
  1576. outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
  1577. outPlane.dist -= outPlane.normal.x * vecInvTranslation[0] + outPlane.normal.y * vecInvTranslation[1] + outPlane.normal.z * vecInvTranslation[2];
  1578. }
  1579. int CeilPow2( int in );
  1580. int FloorPow2( int in );
  1581. FORCEINLINE float * UnpackNormal_HEND3N( const unsigned int *pPackedNormal, float *pNormal )
  1582. {
  1583. int temp[3];
  1584. temp[0] = ((*pPackedNormal >> 0L) & 0x7ff);
  1585. if ( temp[0] & 0x400 )
  1586. {
  1587. temp[0] = 2048 - temp[0];
  1588. }
  1589. temp[1] = ((*pPackedNormal >> 11L) & 0x7ff);
  1590. if ( temp[1] & 0x400 )
  1591. {
  1592. temp[1] = 2048 - temp[1];
  1593. }
  1594. temp[2] = ((*pPackedNormal >> 22L) & 0x3ff);
  1595. if ( temp[2] & 0x200 )
  1596. {
  1597. temp[2] = 1024 - temp[2];
  1598. }
  1599. pNormal[0] = (float)temp[0] * 1.0f/1023.0f;
  1600. pNormal[1] = (float)temp[1] * 1.0f/1023.0f;
  1601. pNormal[2] = (float)temp[2] * 1.0f/511.0f;
  1602. return pNormal;
  1603. }
  1604. FORCEINLINE unsigned int * PackNormal_HEND3N( const float *pNormal, unsigned int *pPackedNormal )
  1605. {
  1606. int temp[3];
  1607. temp[0] = Float2Int( pNormal[0] * 1023.0f );
  1608. temp[1] = Float2Int( pNormal[1] * 1023.0f );
  1609. temp[2] = Float2Int( pNormal[2] * 511.0f );
  1610. // the normal is out of bounds, determine the source and fix
  1611. // clamping would be even more of a slowdown here
  1612. Assert( temp[0] >= -1023 && temp[0] <= 1023 );
  1613. Assert( temp[1] >= -1023 && temp[1] <= 1023 );
  1614. Assert( temp[2] >= -511 && temp[2] <= 511 );
  1615. *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) |
  1616. ( ( temp[1] & 0x7ff ) << 11L ) |
  1617. ( ( temp[0] & 0x7ff ) << 0L );
  1618. return pPackedNormal;
  1619. }
  1620. FORCEINLINE unsigned int * PackNormal_HEND3N( float nx, float ny, float nz, unsigned int *pPackedNormal )
  1621. {
  1622. int temp[3];
  1623. temp[0] = Float2Int( nx * 1023.0f );
  1624. temp[1] = Float2Int( ny * 1023.0f );
  1625. temp[2] = Float2Int( nz * 511.0f );
  1626. // the normal is out of bounds, determine the source and fix
  1627. // clamping would be even more of a slowdown here
  1628. Assert( temp[0] >= -1023 && temp[0] <= 1023 );
  1629. Assert( temp[1] >= -1023 && temp[1] <= 1023 );
  1630. Assert( temp[2] >= -511 && temp[2] <= 511 );
  1631. *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) |
  1632. ( ( temp[1] & 0x7ff ) << 11L ) |
  1633. ( ( temp[0] & 0x7ff ) << 0L );
  1634. return pPackedNormal;
  1635. }
  1636. FORCEINLINE float * UnpackNormal_SHORT2( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE )
  1637. {
  1638. // Unpacks from Jason's 2-short format (fills in a 4th binormal-sign (+1/-1) value, if this is a tangent vector)
  1639. // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits)
  1640. short iX = (*pPackedNormal & 0x0000FFFF);
  1641. short iY = (*pPackedNormal & 0xFFFF0000) >> 16;
  1642. float zSign = +1;
  1643. if ( iX < 0 )
  1644. {
  1645. zSign = -1;
  1646. iX = -iX;
  1647. }
  1648. float tSign = +1;
  1649. if ( iY < 0 )
  1650. {
  1651. tSign = -1;
  1652. iY = -iY;
  1653. }
  1654. pNormal[0] = ( iX - 16384.0f ) / 16384.0f;
  1655. pNormal[1] = ( iY - 16384.0f ) / 16384.0f;
  1656. pNormal[2] = zSign*sqrtf( 1.0f - ( pNormal[0]*pNormal[0] + pNormal[1]*pNormal[1] ) );
  1657. if ( bIsTangent )
  1658. {
  1659. pNormal[3] = tSign;
  1660. }
  1661. return pNormal;
  1662. }
  1663. FORCEINLINE unsigned int * PackNormal_SHORT2( float nx, float ny, float nz, unsigned int *pPackedNormal, float binormalSign = +1.0f )
  1664. {
  1665. // Pack a vector (ASSUMED TO BE NORMALIZED) into Jason's 4-byte (SHORT2) format.
  1666. // This simply reconstructs Z from X & Y. It uses the sign bits of the X & Y coords
  1667. // to reconstruct the sign of Z and, if this is a tangent vector, the sign of the
  1668. // binormal (this is needed because tangent/binormal vectors are supposed to follow
  1669. // UV gradients, but shaders reconstruct the binormal from the tangent and normal
  1670. // assuming that they form a right-handed basis).
  1671. nx += 1; // [-1,+1] -> [0,2]
  1672. ny += 1;
  1673. nx *= 16384.0f; // [ 0, 2] -> [0,32768]
  1674. ny *= 16384.0f;
  1675. // '0' and '32768' values are invalid encodings
  1676. nx = max( nx, 1.0f ); // Make sure there are no zero values
  1677. ny = max( ny, 1.0f );
  1678. nx = min( nx, 32767.0f ); // Make sure there are no 32768 values
  1679. ny = min( ny, 32767.0f );
  1680. if ( nz < 0.0f )
  1681. nx = -nx; // Set the sign bit for z
  1682. ny *= binormalSign; // Set the sign bit for the binormal (use when encoding a tangent vector)
  1683. // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits), also use Float2Int()
  1684. short sX = (short)nx; // signed short [1,32767]
  1685. short sY = (short)ny;
  1686. *pPackedNormal = ( sX & 0x0000FFFF ) | ( sY << 16 ); // NOTE: The mask is necessary (if sX is negative and cast to an int...)
  1687. return pPackedNormal;
  1688. }
  1689. FORCEINLINE unsigned int * PackNormal_SHORT2( const float *pNormal, unsigned int *pPackedNormal, float binormalSign = +1.0f )
  1690. {
  1691. return PackNormal_SHORT2( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, binormalSign );
  1692. }
  1693. // Unpacks a UBYTE4 normal (for a tangent, the result's fourth component receives the binormal 'sign')
  1694. FORCEINLINE float * UnpackNormal_UBYTE4( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE )
  1695. {
  1696. unsigned char cX, cY;
  1697. if ( bIsTangent )
  1698. {
  1699. cX = *pPackedNormal >> 16; // Unpack Z
  1700. cY = *pPackedNormal >> 24; // Unpack W
  1701. }
  1702. else
  1703. {
  1704. cX = *pPackedNormal >> 0; // Unpack X
  1705. cY = *pPackedNormal >> 8; // Unpack Y
  1706. }
  1707. float x = cX - 128.0f;
  1708. float y = cY - 128.0f;
  1709. float z;
  1710. float zSignBit = x < 0 ? 1.0f : 0.0f; // z and t negative bits (like slt asm instruction)
  1711. float tSignBit = y < 0 ? 1.0f : 0.0f;
  1712. float zSign = -( 2*zSignBit - 1 ); // z and t signs
  1713. float tSign = -( 2*tSignBit - 1 );
  1714. x = x*zSign - zSignBit; // 0..127
  1715. y = y*tSign - tSignBit;
  1716. x = x - 64; // -64..63
  1717. y = y - 64;
  1718. float xSignBit = x < 0 ? 1.0f : 0.0f; // x and y negative bits (like slt asm instruction)
  1719. float ySignBit = y < 0 ? 1.0f : 0.0f;
  1720. float xSign = -( 2*xSignBit - 1 ); // x and y signs
  1721. float ySign = -( 2*ySignBit - 1 );
  1722. x = ( x*xSign - xSignBit ) / 63.0f; // 0..1 range
  1723. y = ( y*ySign - ySignBit ) / 63.0f;
  1724. z = 1.0f - x - y;
  1725. float oolen = 1.0f / sqrt( x*x + y*y + z*z ); // Normalize and
  1726. x *= oolen * xSign; // Recover signs
  1727. y *= oolen * ySign;
  1728. z *= oolen * zSign;
  1729. pNormal[0] = x;
  1730. pNormal[1] = y;
  1731. pNormal[2] = z;
  1732. if ( bIsTangent )
  1733. {
  1734. pNormal[3] = tSign;
  1735. }
  1736. return pNormal;
  1737. }
  1738. //////////////////////////////////////////////////////////////////////////////
  1739. // See: http://www.oroboro.com/rafael/docserv.php/index/programming/article/unitv2
  1740. //
  1741. // UBYTE4 encoding, using per-octant projection onto x+y+z=1
  1742. // Assume input vector is already unit length
  1743. //
  1744. // binormalSign specifies 'sign' of binormal, stored in t sign bit of tangent
  1745. // (lets the shader know whether norm/tan/bin form a right-handed basis)
  1746. //
  1747. // bIsTangent is used to specify which WORD of the output to store the data
  1748. // The expected usage is to call once with the normal and once with
  1749. // the tangent and binormal sign flag, bitwise OR'ing the returned DWORDs
  1750. FORCEINLINE unsigned int * PackNormal_UBYTE4( float nx, float ny, float nz, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f )
  1751. {
  1752. float xSign = nx < 0.0f ? -1.0f : 1.0f; // -1 or 1 sign
  1753. float ySign = ny < 0.0f ? -1.0f : 1.0f;
  1754. float zSign = nz < 0.0f ? -1.0f : 1.0f;
  1755. float tSign = binormalSign;
  1756. Assert( ( binormalSign == +1.0f ) || ( binormalSign == -1.0f ) );
  1757. float xSignBit = 0.5f*( 1 - xSign ); // [-1,+1] -> [1,0]
  1758. float ySignBit = 0.5f*( 1 - ySign ); // 1 is negative bit (like slt instruction)
  1759. float zSignBit = 0.5f*( 1 - zSign );
  1760. float tSignBit = 0.5f*( 1 - binormalSign );
  1761. float absX = xSign*nx; // 0..1 range (abs)
  1762. float absY = ySign*ny;
  1763. float absZ = zSign*nz;
  1764. float xbits = absX / ( absX + absY + absZ ); // Project onto x+y+z=1 plane
  1765. float ybits = absY / ( absX + absY + absZ );
  1766. xbits *= 63; // 0..63
  1767. ybits *= 63;
  1768. xbits = xbits * xSign - xSignBit; // -64..63 range
  1769. ybits = ybits * ySign - ySignBit;
  1770. xbits += 64.0f; // 0..127 range
  1771. ybits += 64.0f;
  1772. xbits = xbits * zSign - zSignBit; // Negate based on z and t
  1773. ybits = ybits * tSign - tSignBit; // -128..127 range
  1774. xbits += 128.0f; // 0..255 range
  1775. ybits += 128.0f;
  1776. unsigned char cX = (unsigned char) xbits;
  1777. unsigned char cY = (unsigned char) ybits;
  1778. if ( !bIsTangent )
  1779. *pPackedNormal = (cX << 0) | (cY << 8); // xy for normal
  1780. else
  1781. *pPackedNormal = (cX << 16) | (cY << 24); // zw for tangent
  1782. return pPackedNormal;
  1783. }
  1784. FORCEINLINE unsigned int * PackNormal_UBYTE4( const float *pNormal, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f )
  1785. {
  1786. return PackNormal_UBYTE4( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, bIsTangent, binormalSign );
  1787. }
  1788. //-----------------------------------------------------------------------------
  1789. // Convert RGB to HSV
  1790. //-----------------------------------------------------------------------------
  1791. void RGBtoHSV( const Vector &rgb, Vector &hsv );
  1792. //-----------------------------------------------------------------------------
  1793. // Convert HSV to RGB
  1794. //-----------------------------------------------------------------------------
  1795. void HSVtoRGB( const Vector &hsv, Vector &rgb );
  1796. //-----------------------------------------------------------------------------
  1797. // Fast version of pow and log
  1798. //-----------------------------------------------------------------------------
  1799. float FastLog2(float i); // log2( i )
  1800. float FastPow2(float i); // 2^i
  1801. float FastPow(float a, float b); // a^b
  1802. float FastPow10( float i ); // 10^i
  1803. //-----------------------------------------------------------------------------
  1804. // For testing float equality
  1805. //-----------------------------------------------------------------------------
  1806. inline bool CloseEnough( float a, float b, float epsilon = EQUAL_EPSILON )
  1807. {
  1808. return fabs( a - b ) <= epsilon;
  1809. }
  1810. inline bool CloseEnough( const Vector &a, const Vector &b, float epsilon = EQUAL_EPSILON )
  1811. {
  1812. return fabs( a.x - b.x ) <= epsilon &&
  1813. fabs( a.y - b.y ) <= epsilon &&
  1814. fabs( a.z - b.z ) <= epsilon;
  1815. }
  1816. // Fast compare
  1817. // maxUlps is the maximum error in terms of Units in the Last Place. This
  1818. // specifies how big an error we are willing to accept in terms of the value
  1819. // of the least significant digit of the floating point number�s
  1820. // representation. maxUlps can also be interpreted in terms of how many
  1821. // representable floats we are willing to accept between A and B.
  1822. // This function will allow maxUlps-1 floats between A and B.
  1823. bool AlmostEqual(float a, float b, int maxUlps = 10);
  1824. inline bool AlmostEqual( const Vector &a, const Vector &b, int maxUlps = 10)
  1825. {
  1826. return AlmostEqual( a.x, b.x, maxUlps ) &&
  1827. AlmostEqual( a.y, b.y, maxUlps ) &&
  1828. AlmostEqual( a.z, b.z, maxUlps );
  1829. }
  1830. #endif // MATH_BASE_H