Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3133 lines
95 KiB

  1. //===== Copyright 1996-2005, 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 "tier0/basetypes.h"
  10. #include "mathlib/vector.h"
  11. #include "mathlib/vector2d.h"
  12. #include "tier0/dbg.h"
  13. #include "mathlib/math_pfns.h"
  14. #include "mathlib/fltx4.h"
  15. #ifndef ALIGN8_POST
  16. #define ALIGN8_POST
  17. #endif
  18. #if defined(_PS3)
  19. #if defined(__SPU__)
  20. #include <spu_intrinsics.h>
  21. #include <vmx2spu.h>
  22. #include <vectormath/c/vectormath_soa.h>
  23. #else
  24. #include <ppu_intrinsics.h>
  25. #include <altivec.h>
  26. #include <vectormath/c/vectormath_soa.h>
  27. #endif
  28. #endif
  29. // plane_t structure
  30. // !!! if this is changed, it must be changed in asm code too !!!
  31. // FIXME: does the asm code even exist anymore?
  32. // FIXME: this should move to a different file
  33. struct cplane_t
  34. {
  35. Vector normal;
  36. float dist;
  37. byte type; // for fast side tests
  38. byte signbits; // signx + (signy<<1) + (signz<<1)
  39. byte pad[2];
  40. #ifdef VECTOR_NO_SLOW_OPERATIONS
  41. cplane_t() {}
  42. private:
  43. // No copy constructors allowed if we're in optimal mode
  44. cplane_t(const cplane_t& vOther);
  45. #endif
  46. };
  47. // structure offset for asm code
  48. #define CPLANE_NORMAL_X 0
  49. #define CPLANE_NORMAL_Y 4
  50. #define CPLANE_NORMAL_Z 8
  51. #define CPLANE_DIST 12
  52. #define CPLANE_TYPE 16
  53. #define CPLANE_SIGNBITS 17
  54. #define CPLANE_PAD0 18
  55. #define CPLANE_PAD1 19
  56. // 0-2 are axial planes
  57. #define PLANE_X 0
  58. #define PLANE_Y 1
  59. #define PLANE_Z 2
  60. // 3-5 are non-axial planes snapped to the nearest
  61. #define PLANE_ANYX 3
  62. #define PLANE_ANYY 4
  63. #define PLANE_ANYZ 5
  64. //-----------------------------------------------------------------------------
  65. // Frustum plane indices.
  66. // WARNING: there is code that depends on these values
  67. //-----------------------------------------------------------------------------
  68. enum
  69. {
  70. FRUSTUM_RIGHT = 0,
  71. FRUSTUM_LEFT = 1,
  72. FRUSTUM_TOP = 2,
  73. FRUSTUM_BOTTOM = 3,
  74. FRUSTUM_NEARZ = 4,
  75. FRUSTUM_FARZ = 5,
  76. FRUSTUM_NUMPLANES = 6
  77. };
  78. extern int SignbitsForPlane( cplane_t *out );
  79. class Frustum_t;
  80. // Computes Y fov from an X fov and a screen aspect ratio + X from Y
  81. float CalcFovY( float flFovX, float flScreenAspect );
  82. float CalcFovX( float flFovY, float flScreenAspect );
  83. // Generate a frustum based on perspective view parameters
  84. // NOTE: FOV is specified in degrees, as the *full* view angle (not half-angle)
  85. class VPlane;
  86. void GeneratePerspectiveFrustum( const Vector& origin, const QAngle &angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t &frustum );
  87. void GeneratePerspectiveFrustum( const Vector& origin, const Vector &forward, const Vector &right, const Vector &up, float flZNear, float flZFar, float flFovX, float flFovY, VPlane *pPlanesOut );
  88. // Cull the world-space bounding box to the specified frustum.
  89. // bool R_CullBox( const Vector& mins, const Vector& maxs, const Frustum_t &frustum );
  90. // bool R_CullBoxSkipNear( const Vector& mins, const Vector& maxs, const Frustum_t &frustum );
  91. void GenerateOrthoFrustum( const Vector &origin, const Vector &forward, const Vector &right, const Vector &up, float flLeft, float flRight, float flBottom, float flTop, float flZNear, float flZFar, VPlane *pPlanesOut );
  92. class CTransform;
  93. class matrix3x4a_t;
  94. struct matrix3x4_t
  95. {
  96. matrix3x4_t() {}
  97. matrix3x4_t(
  98. float m00, float m01, float m02, float m03,
  99. float m10, float m11, float m12, float m13,
  100. float m20, float m21, float m22, float m23 )
  101. {
  102. m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03;
  103. m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13;
  104. m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23;
  105. }
  106. /// Creates a matrix where the X axis = forward the Y axis = left, and the Z axis = up
  107. void InitXYZ( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
  108. {
  109. m_flMatVal[ 0 ][ 0 ] = xAxis.x; m_flMatVal[ 0 ][ 1 ] = yAxis.x; m_flMatVal[ 0 ][ 2 ] = zAxis.x; m_flMatVal[ 0 ][ 3 ] = vecOrigin.x;
  110. m_flMatVal[ 1 ][ 0 ] = xAxis.y; m_flMatVal[ 1 ][ 1 ] = yAxis.y; m_flMatVal[ 1 ][ 2 ] = zAxis.y; m_flMatVal[ 1 ][ 3 ] = vecOrigin.y;
  111. m_flMatVal[ 2 ][ 0 ] = xAxis.z; m_flMatVal[ 2 ][ 1 ] = yAxis.z; m_flMatVal[ 2 ][ 2 ] = zAxis.z; m_flMatVal[ 2 ][ 3 ] = vecOrigin.z;
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Creates a matrix where the X axis = forward
  115. // the Y axis = left, and the Z axis = up
  116. //-----------------------------------------------------------------------------
  117. void Init( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
  118. {
  119. m_flMatVal[0][0] = xAxis.x; m_flMatVal[0][1] = yAxis.x; m_flMatVal[0][2] = zAxis.x; m_flMatVal[0][3] = vecOrigin.x;
  120. m_flMatVal[1][0] = xAxis.y; m_flMatVal[1][1] = yAxis.y; m_flMatVal[1][2] = zAxis.y; m_flMatVal[1][3] = vecOrigin.y;
  121. m_flMatVal[2][0] = xAxis.z; m_flMatVal[2][1] = yAxis.z; m_flMatVal[2][2] = zAxis.z; m_flMatVal[2][3] = vecOrigin.z;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Creates a matrix where the X axis = forward
  125. // the Y axis = left, and the Z axis = up
  126. //-----------------------------------------------------------------------------
  127. matrix3x4_t( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
  128. {
  129. Init( xAxis, yAxis, zAxis, vecOrigin );
  130. }
  131. inline void InitFromQAngles( const QAngle &angles, const Vector &vPosition );
  132. inline void InitFromQAngles( const QAngle &angles );
  133. inline void InitFromRadianEuler( const RadianEuler &angles, const Vector &vPosition );
  134. inline void InitFromRadianEuler( const RadianEuler &angles );
  135. inline void InitFromCTransform( const CTransform &transform );
  136. inline void InitFromQuaternion( const Quaternion &orientation, const Vector &vPosition );
  137. inline void InitFromQuaternion( const Quaternion &orientation );
  138. inline void InitFromDiagonal( const Vector &vDiagonal );
  139. inline Quaternion ToQuaternion() const;
  140. inline QAngle ToQAngle() const;
  141. inline CTransform ToCTransform() const;
  142. inline void SetToIdentity();
  143. /// multiply the scale/rot part of the matrix by a constant. This doesn't init the matrix ,
  144. /// just scale in place. So if you want to construct a scaling matrix, init to identity and
  145. /// then call this.
  146. FORCEINLINE void ScaleUpper3x3Matrix( float flScale );
  147. /// modify the origin
  148. inline void SetOrigin( Vector const & p )
  149. {
  150. m_flMatVal[0][3] = p.x;
  151. m_flMatVal[1][3] = p.y;
  152. m_flMatVal[2][3] = p.z;
  153. }
  154. /// return the origin
  155. inline Vector GetOrigin( void ) const
  156. {
  157. Vector vecRet( m_flMatVal[ 0 ][ 3 ], m_flMatVal[ 1 ][ 3 ], m_flMatVal[ 2 ][ 3 ] );
  158. return vecRet;
  159. }
  160. inline void Invalidate( void )
  161. {
  162. for (int i = 0; i < 3; i++)
  163. {
  164. for (int j = 0; j < 4; j++)
  165. {
  166. m_flMatVal[i][j] = VEC_T_NAN;
  167. }
  168. }
  169. }
  170. /// check all components for invalid floating point values
  171. inline bool IsValid( void ) const
  172. {
  173. for (int i = 0; i < 3; i++)
  174. {
  175. for (int j = 0; j < 4; j++)
  176. {
  177. if ( !IsFinite( m_flMatVal[i][j] ) )
  178. return false;
  179. }
  180. }
  181. return true;
  182. }
  183. bool operator==( const matrix3x4_t &other ) const
  184. {
  185. return memcmp( this, &other, sizeof(matrix3x4_t) ) == 0;
  186. }
  187. bool operator!=( const matrix3x4_t &other ) const
  188. {
  189. return memcmp( this, &other, sizeof(matrix3x4_t) ) != 0;
  190. }
  191. inline bool IsEqualTo( const matrix3x4_t &other, float flTolerance = 1e-5f ) const;
  192. inline void GetBasisVectorsFLU( Vector *pForward, Vector *pLeft, Vector *pUp ) const;
  193. inline Vector TransformVector( const Vector &v0 ) const;
  194. inline Vector RotateVector( const Vector &v0 ) const;
  195. inline Vector TransformVectorByInverse( const Vector &v0 ) const;
  196. inline Vector RotateVectorByInverse( const Vector &v0 ) const;
  197. inline Vector RotateExtents( const Vector &vBoxExtents ) const; // these are extents and must remain positive/symmetric after rotation
  198. inline void TransformAABB( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const;
  199. inline void TransformAABBByInverse( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const;
  200. inline void RotateAABB( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const;
  201. inline void RotateAABBByInverse( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const;
  202. inline void TransformPlane( const cplane_t &inPlane, cplane_t &outPlane ) const;
  203. inline void TransformPlaneByInverse( const cplane_t &inPlane, cplane_t &outPlane ) const;
  204. inline float GetOrthogonalityError() const;
  205. inline float GetDeterminant( )const;
  206. inline float GetSylvestersCriterion()const; // for symmetrical matrices only: should be >0 iff it's a positive definite matrix
  207. inline Vector GetColumn( MatrixAxisType_t nColumn ) const;
  208. inline void SetColumn( const Vector &vColumn, MatrixAxisType_t nColumn );
  209. inline Vector GetForward() const { return GetColumn( FORWARD_AXIS ); }
  210. inline Vector GetLeft() const { return GetColumn( LEFT_AXIS ); }
  211. inline Vector GetUp() const { return GetColumn( UP_AXIS ); }
  212. inline Vector GetRow( int nRow ) const { return *(Vector *)(m_flMatVal[nRow]); }
  213. inline void SetRow( int nRow, const Vector &vRow ) { m_flMatVal[nRow][0] = vRow.x; m_flMatVal[nRow][1] = vRow.y; m_flMatVal[nRow][2] = vRow.z; }
  214. inline void InverseTR( matrix3x4_t &out ) const;
  215. inline matrix3x4_t InverseTR() const;
  216. float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; }
  217. const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; }
  218. float *Base() { return &m_flMatVal[0][0]; }
  219. const float *Base() const { return &m_flMatVal[0][0]; }
  220. float m_flMatVal[3][4];
  221. };
  222. class ALIGN16 matrix3x4a_t : public matrix3x4_t
  223. {
  224. public:
  225. /*
  226. matrix3x4a_t() { if (((size_t)Base()) % 16 != 0) { Error( "matrix3x4a_t missaligned" ); } }
  227. */
  228. matrix3x4a_t( const matrix3x4_t& src ) { *this = src; };
  229. matrix3x4a_t& operator=( const matrix3x4_t& src ) { memcpy( Base(), src.Base(), sizeof( float ) * 3 * 4 ); return *this; };
  230. matrix3x4a_t(
  231. float m00, float m01, float m02, float m03,
  232. float m10, float m11, float m12, float m13,
  233. float m20, float m21, float m22, float m23 )
  234. {
  235. AssertDbg( ( ( size_t )Base() & 0xf ) == 0 );
  236. m_flMatVal[ 0 ][ 0 ] = m00; m_flMatVal[ 0 ][ 1 ] = m01; m_flMatVal[ 0 ][ 2 ] = m02; m_flMatVal[ 0 ][ 3 ] = m03;
  237. m_flMatVal[ 1 ][ 0 ] = m10; m_flMatVal[ 1 ][ 1 ] = m11; m_flMatVal[ 1 ][ 2 ] = m12; m_flMatVal[ 1 ][ 3 ] = m13;
  238. m_flMatVal[ 2 ][ 0 ] = m20; m_flMatVal[ 2 ][ 1 ] = m21; m_flMatVal[ 2 ][ 2 ] = m22; m_flMatVal[ 2 ][ 3 ] = m23;
  239. }
  240. matrix3x4a_t(){}
  241. static FORCEINLINE bool TypeIsAlignedForSIMD( void ) { return true; }
  242. // raw data simd accessor
  243. FORCEINLINE fltx4 &SIMDRow( uint nIdx ) { AssertDbg( nIdx < 3 ); return *( ( fltx4 * )( &( m_flMatVal[ nIdx ] ) ) ); }
  244. FORCEINLINE const fltx4 &SIMDRow( uint nIdx ) const { AssertDbg( nIdx < 3 ); return *( ( const fltx4 * )( &( m_flMatVal[ nIdx ] ) ) ); }
  245. } ALIGN16_POST;
  246. FORCEINLINE void matrix3x4_t::ScaleUpper3x3Matrix( float flScale )
  247. {
  248. for ( int i = 0; i < 3; i++ )
  249. {
  250. for ( int j = 0; j < 3; j++ )
  251. {
  252. m_flMatVal[ i ][ j ] *= flScale;
  253. }
  254. }
  255. }
  256. #ifndef M_PI
  257. #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
  258. #endif
  259. #ifndef M_PI_F
  260. #define M_PI_F ((float)(M_PI))
  261. #endif
  262. // NJS: Inlined to prevent floats from being autopromoted to doubles, as with the old system.
  263. #ifndef RAD2DEG
  264. #define RAD2DEG( x ) ( (float)(x) * (float)(180.f / M_PI_F) )
  265. #endif
  266. #ifndef DEG2RAD
  267. #define DEG2RAD( x ) ( (float)(x) * (float)(M_PI_F / 180.f) )
  268. #endif
  269. // Used to represent sides of things like planes.
  270. #define SIDE_FRONT 0
  271. #define SIDE_BACK 1
  272. #define SIDE_ON 2
  273. #define SIDE_CROSS -2 // necessary for polylib.c
  274. // Use different side values (1, 2, 4) instead of (0, 1, 2) so we can '|' and '&' them, and quickly determine overall clipping
  275. // without having to maintain counters and read / write memory.
  276. enum Sides
  277. {
  278. OR_SIDE_FRONT = 1,
  279. OR_SIDE_BACK = 2,
  280. OR_SIDE_ON = 4,
  281. };
  282. #define ON_VIS_EPSILON 0.01 // necessary for vvis (flow.c) -- again look into moving later!
  283. #define EQUAL_EPSILON 0.001 // necessary for vbsp (faces.c) -- should look into moving it there?
  284. extern bool s_bMathlibInitialized;
  285. extern const matrix3x4a_t g_MatrixIdentity;
  286. extern const Vector vec3_origin;
  287. extern const QAngle vec3_angle;
  288. extern const Quaternion quat_identity;
  289. extern const Vector vec3_invalid;
  290. extern const int nanmask;
  291. #define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
  292. FORCEINLINE vec_t DotProduct(const vec_t *v1, const vec_t *v2)
  293. {
  294. return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
  295. }
  296. FORCEINLINE void VectorSubtract(const vec_t *a, const vec_t *b, vec_t *c)
  297. {
  298. c[0]=a[0]-b[0];
  299. c[1]=a[1]-b[1];
  300. c[2]=a[2]-b[2];
  301. }
  302. FORCEINLINE void VectorAdd(const vec_t *a, const vec_t *b, vec_t *c)
  303. {
  304. c[0]=a[0]+b[0];
  305. c[1]=a[1]+b[1];
  306. c[2]=a[2]+b[2];
  307. }
  308. FORCEINLINE void VectorCopy(const vec_t *a, vec_t *b)
  309. {
  310. b[0]=a[0];
  311. b[1]=a[1];
  312. b[2]=a[2];
  313. }
  314. FORCEINLINE void VectorClear(vec_t *a)
  315. {
  316. a[0]=a[1]=a[2]=0;
  317. }
  318. FORCEINLINE float VectorMaximum(const vec_t *v)
  319. {
  320. return MAX( v[0], MAX( v[1], v[2] ) );
  321. }
  322. FORCEINLINE float VectorMaximum(const Vector& v)
  323. {
  324. return MAX( v.x, MAX( v.y, v.z ) );
  325. }
  326. FORCEINLINE void VectorScale (const float* in, vec_t scale, float* out)
  327. {
  328. out[0] = in[0]*scale;
  329. out[1] = in[1]*scale;
  330. out[2] = in[2]*scale;
  331. }
  332. // Cannot be forceinline as they have overloads:
  333. inline void VectorFill(vec_t *a, float b)
  334. {
  335. a[0]=a[1]=a[2]=b;
  336. }
  337. inline void VectorNegate(vec_t *a)
  338. {
  339. a[0]=-a[0];
  340. a[1]=-a[1];
  341. a[2]=-a[2];
  342. }
  343. //#define VectorMaximum(a) ( max( (a)[0], max( (a)[1], (a)[2] ) ) )
  344. #define Vector2Clear(x) {(x)[0]=(x)[1]=0;}
  345. #define Vector2Negate(x) {(x)[0]=-((x)[0]);(x)[1]=-((x)[1]);}
  346. #define Vector2Copy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];}
  347. #define Vector2Subtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];}
  348. #define Vector2Add(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];}
  349. #define Vector2Scale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];}
  350. // NJS: Some functions in VBSP still need to use these for dealing with mixing vec4's and shorts with vec_t's.
  351. // remove when no longer needed.
  352. #define VECTOR_COPY( A, B ) do { (B)[0] = (A)[0]; (B)[1] = (A)[1]; (B)[2]=(A)[2]; } while(0)
  353. #define DOT_PRODUCT( A, B ) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] )
  354. FORCEINLINE void VectorMAInline( const float* start, float scale, const float* direction, float* dest )
  355. {
  356. dest[0]=start[0]+direction[0]*scale;
  357. dest[1]=start[1]+direction[1]*scale;
  358. dest[2]=start[2]+direction[2]*scale;
  359. }
  360. FORCEINLINE void VectorMAInline( const Vector& start, float scale, const Vector& direction, Vector& dest )
  361. {
  362. dest.x=start.x+direction.x*scale;
  363. dest.y=start.y+direction.y*scale;
  364. dest.z=start.z+direction.z*scale;
  365. }
  366. FORCEINLINE void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest )
  367. {
  368. VectorMAInline(start, scale, direction, dest);
  369. }
  370. FORCEINLINE void VectorMA( const float * start, float scale, const float *direction, float *dest )
  371. {
  372. VectorMAInline(start, scale, direction, dest);
  373. }
  374. int VectorCompare (const float *v1, const float *v2);
  375. inline float VectorLength(const float *v)
  376. {
  377. return FastSqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + FLT_EPSILON );
  378. }
  379. void CrossProduct (const float *v1, const float *v2, float *cross);
  380. inline float CrossProductX( const Vector & v1, const Vector& v2 )
  381. {
  382. return v1.y * v2.z - v1.z * v2.y;
  383. }
  384. inline float CrossProductY( const Vector & v1, const Vector& v2 )
  385. {
  386. return v1.z * v2.x - v1.x * v2.z;
  387. }
  388. inline float CrossProductZ( const Vector & v1, const Vector& v2 )
  389. {
  390. return v1.x * v2.y - v1.y * v2.x;
  391. }
  392. qboolean VectorsEqual( const float *v1, const float *v2 );
  393. inline vec_t RoundInt (vec_t in)
  394. {
  395. return floor(in + 0.5f);
  396. }
  397. size_t Q_log2( unsigned int val );
  398. // Math routines done in optimized assembly math package routines
  399. void inline SinCos( float radians, float * RESTRICT sine, float * RESTRICT cosine )
  400. {
  401. #if defined( _X360 )
  402. XMScalarSinCos( sine, cosine, radians );
  403. #elif defined( _PS3 )
  404. #if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 )
  405. vector_float_union s;
  406. vector_float_union c;
  407. vec_float4 rad = vec_splats( radians );
  408. vec_float4 sin;
  409. vec_float4 cos;
  410. sincosf4( rad, &sin, &cos );
  411. vec_st( sin, 0, s.f );
  412. vec_st( cos, 0, c.f );
  413. *sine = s.f[0];
  414. *cosine = c.f[0];
  415. #else //__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 1
  416. vector_float_union r;
  417. vector_float_union s;
  418. vector_float_union c;
  419. vec_float4 rad;
  420. vec_float4 sin;
  421. vec_float4 cos;
  422. r.f[0] = radians;
  423. rad = vec_ld( 0, r.f );
  424. sincosf4( rad, &sin, &cos );
  425. vec_st( sin, 0, s.f );
  426. vec_st( cos, 0, c.f );
  427. *sine = s.f[0];
  428. *cosine = c.f[0];
  429. #endif //__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 1
  430. #elif defined( COMPILER_MSVC32 )
  431. _asm
  432. {
  433. fld DWORD PTR [radians]
  434. fsincos
  435. mov edx, DWORD PTR [cosine]
  436. mov eax, DWORD PTR [sine]
  437. fstp DWORD PTR [edx]
  438. fstp DWORD PTR [eax]
  439. }
  440. #elif defined( GNUC )
  441. register double __cosr, __sinr;
  442. __asm __volatile__ ("fsincos" : "=t" (__cosr), "=u" (__sinr) : "0" (radians));
  443. *sine = __sinr;
  444. *cosine = __cosr;
  445. #else
  446. *sine = sinf(radians);
  447. *cosine = cosf(radians);
  448. #endif
  449. }
  450. #define SIN_TABLE_SIZE 256
  451. #define FTOIBIAS 12582912.f
  452. extern float SinCosTable[SIN_TABLE_SIZE];
  453. inline float TableCos( float theta )
  454. {
  455. #if defined( LINUX )
  456. return cos(theta); // under the GCC compiler the float-represented-as-an-int causes an internal compiler error
  457. #else
  458. union
  459. {
  460. int i;
  461. float f;
  462. } ftmp;
  463. // ideally, the following should compile down to: theta * constant + constant, changing any of these constants from defines sometimes fubars this.
  464. ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + ( FTOIBIAS + ( SIN_TABLE_SIZE / 4 ) );
  465. return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ];
  466. #endif
  467. }
  468. inline float TableSin( float theta )
  469. {
  470. #if defined( LINUX )
  471. return sin(theta); // under the GCC compiler the float-represented-as-an-int causes an internal compiler error
  472. #else
  473. union
  474. {
  475. int i;
  476. float f;
  477. } ftmp;
  478. // ideally, the following should compile down to: theta * constant + constant
  479. ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + FTOIBIAS;
  480. return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ];
  481. #endif
  482. }
  483. template<class T>
  484. FORCEINLINE T Square( T const &a )
  485. {
  486. return a * a;
  487. }
  488. FORCEINLINE bool IsPowerOfTwo( uint x )
  489. {
  490. return ( x & ( x - 1 ) ) == 0;
  491. }
  492. // return the smallest power of two >= x.
  493. // returns 0 if x == 0 or x > 0x80000000 (ie numbers that would be negative if x was signed)
  494. // NOTE: the old code took an int, and if you pass in an int of 0x80000000 casted to a uint,
  495. // you'll get 0x80000000, which is correct for uints, instead of 0, which was correct for ints
  496. FORCEINLINE uint SmallestPowerOfTwoGreaterOrEqual( uint x )
  497. {
  498. x -= 1;
  499. x |= x >> 1;
  500. x |= x >> 2;
  501. x |= x >> 4;
  502. x |= x >> 8;
  503. x |= x >> 16;
  504. return x + 1;
  505. }
  506. // return the largest power of two <= x. Will return 0 if passed 0
  507. FORCEINLINE uint LargestPowerOfTwoLessThanOrEqual( uint x )
  508. {
  509. if ( x >= 0x80000000 )
  510. return 0x80000000;
  511. return SmallestPowerOfTwoGreaterOrEqual( x + 1 ) >> 1;
  512. }
  513. // Math routines for optimizing division
  514. void FloorDivMod (double numer, double denom, int *quotient, int *rem);
  515. int GreatestCommonDivisor (int i1, int i2);
  516. // Test for FPU denormal mode
  517. bool IsDenormal( const float &val );
  518. // MOVEMENT INFO
  519. enum
  520. {
  521. PITCH = 0, // up / down
  522. YAW, // left / right
  523. ROLL // fall over
  524. };
  525. void MatrixVectorsFLU( const matrix3x4_t &matrix, Vector* pForward, Vector *pLeft, Vector *pUp );
  526. void MatrixAngles( const matrix3x4_t & matrix, float *angles ); // !!!!
  527. void MatrixVectors( const matrix3x4_t &matrix, Vector* pForward, Vector *pRight, Vector *pUp );
  528. void VectorTransform (const float *in1, const matrix3x4_t & in2, float *out);
  529. void VectorITransform (const float *in1, const matrix3x4_t & in2, float *out);
  530. void VectorRotate( const float *in1, const matrix3x4_t & in2, float *out);
  531. void VectorRotate( const Vector &in1, const QAngle &in2, Vector &out );
  532. void VectorRotate( const Vector &in1, const Quaternion &in2, Vector &out );
  533. void VectorIRotate( const float *in1, const matrix3x4_t & in2, float *out);
  534. inline const Vector VectorRotate( const Vector &vIn1, const Quaternion &qIn2 )
  535. {
  536. Vector out;
  537. VectorRotate( vIn1, qIn2, out );
  538. return out;
  539. }
  540. #ifndef VECTOR_NO_SLOW_OPERATIONS
  541. QAngle TransformAnglesToLocalSpace( const QAngle &angles, const matrix3x4_t &parentMatrix );
  542. QAngle TransformAnglesToWorldSpace( const QAngle &angles, const matrix3x4_t &parentMatrix );
  543. #endif
  544. void MatrixInitialize( matrix3x4_t &mat, const Vector &vecOrigin, const Vector &vecXAxis, const Vector &vecYAxis, const Vector &vecZAxis );
  545. void MatrixCopy( const matrix3x4_t &in, matrix3x4_t &out );
  546. void MatrixInvert( const matrix3x4_t &in, matrix3x4_t &out );
  547. // Matrix equality test
  548. bool MatricesAreEqual( const matrix3x4_t &src1, const matrix3x4_t &src2, float flTolerance = 1e-5 );
  549. void MatrixGetColumn( const matrix3x4_t &in, int column, Vector &out );
  550. void MatrixSetColumn( const Vector &in, int column, matrix3x4_t &out );
  551. //void DecomposeRotation( const matrix3x4_t &mat, float *out );
  552. void ConcatRotations (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out);
  553. void ConcatTransforms (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out);
  554. // faster version assumes m0, m1, out are 16-byte aligned addresses
  555. void ConcatTransforms_Aligned( const matrix3x4a_t &m0, const matrix3x4a_t &m1, matrix3x4a_t &out );
  556. // For identical interface w/ VMatrix
  557. inline void MatrixMultiply ( const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out )
  558. {
  559. ConcatTransforms( in1, in2, out );
  560. }
  561. void QuaternionExp( const Quaternion &p, Quaternion &q );
  562. void QuaternionLn( const Quaternion &p, Quaternion &q );
  563. void QuaternionAverageExponential( Quaternion &q, int nCount, const Quaternion *pQuaternions, const float *pflWeights = NULL );
  564. void QuaternionLookAt( const Vector &vecForward, const Vector &referenceUp, Quaternion &q );
  565. void QuaternionSlerp( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  566. void QuaternionSlerpNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  567. void QuaternionBlend( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  568. void QuaternionBlendNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
  569. void QuaternionIdentityBlend( const Quaternion &p, float t, Quaternion &qt );
  570. float QuaternionAngleDiff( const Quaternion &p, const Quaternion &q );
  571. void QuaternionScale( const Quaternion &p, float t, Quaternion &q );
  572. void QuaternionAlign( const Quaternion &p, const Quaternion &q, Quaternion &qt );
  573. float QuaternionDotProduct( const Quaternion &p, const Quaternion &q );
  574. void QuaternionConjugate( const Quaternion &p, Quaternion &q );
  575. void QuaternionInvert( const Quaternion &p, Quaternion &q );
  576. float QuaternionNormalize( Quaternion &q );
  577. void QuaternionMultiply( const Quaternion &q, const Vector &v, Vector &result );
  578. void QuaternionAdd( const Quaternion &p, const Quaternion &q, Quaternion &qt );
  579. void QuaternionMult( const Quaternion &p, const Quaternion &q, Quaternion &qt );
  580. void QuaternionMatrix( const Quaternion &q, matrix3x4_t &matrix );
  581. void QuaternionMatrix( const Quaternion &q, const Vector &pos, matrix3x4_t &matrix );
  582. void QuaternionMatrix( const Quaternion &q, const Vector &pos, const Vector &vScale, matrix3x4_t& mat );
  583. void QuaternionAngles( const Quaternion &q, QAngle &angles );
  584. void AngleQuaternion( const QAngle& angles, Quaternion &qt );
  585. void QuaternionAngles( const Quaternion &q, RadianEuler &angles );
  586. void QuaternionVectorsFLU( Quaternion const &q, Vector *pForward, Vector *pLeft, Vector *pUp );
  587. void QuaternionVectorsForward( const Quaternion& q, Vector *pForward );
  588. void AngleQuaternion( RadianEuler const &angles, Quaternion &qt );
  589. void QuaternionAxisAngle( const Quaternion &q, Vector &axis, float &angle );
  590. void AxisAngleQuaternion( const Vector &axis, float angle, Quaternion &q );
  591. void BasisToQuaternion( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Quaternion &q );
  592. void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q );
  593. void MatrixQuaternionFast( const matrix3x4_t &mat, Quaternion &q );
  594. void MatrixPosition( const matrix3x4_t &matrix, Vector &position );
  595. Vector MatrixNormalize( const matrix3x4_t &in, matrix3x4_t &out );
  596. inline void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q, Vector &o )
  597. {
  598. MatrixQuaternion( mat, q );
  599. MatrixPosition( mat, o );
  600. }
  601. float MatrixQuaternionTest( uint );
  602. float MatrixQuaternionTest2( uint );
  603. /// qt = p + s * q
  604. void QuaternionAccumulate( const Quaternion &p, float s, const Quaternion &q, Quaternion &qt );
  605. /// qt = ( s * p ) * q
  606. void QuaternionSM( float s, const Quaternion &p, const Quaternion &q, Quaternion &qt );
  607. /// qt = p * ( s * q )
  608. void QuaternionMA( const Quaternion &p, float s, const Quaternion &q, Quaternion &qt );
  609. /*
  610. //-----------------------------------------------------------------------------
  611. // Quaternion equality with tolerance
  612. //-----------------------------------------------------------------------------
  613. inline bool QuaternionsAreEqualInternal( const Quaternion& src1, const Quaternion& src2, float flTolerance )
  614. {
  615. if ( !FloatsAreEqual( src1.x, src2.x, flTolerance ) )
  616. return false;
  617. if ( !FloatsAreEqual( src1.y, src2.y, flTolerance ) )
  618. return false;
  619. if ( !FloatsAreEqual( src1.z, src2.z, flTolerance ) )
  620. return false;
  621. return FloatsAreEqual( src1.w, src2.w, flTolerance );
  622. }
  623. inline bool QuaternionsAreEqual( const Quaternion& src1, const Quaternion& src2, float flTolerance )
  624. {
  625. if ( QuaternionsAreEqualInternal( src1, src2, flTolerance ) )
  626. return true;
  627. // negated quaternions are also 'equal'
  628. Quaternion src2neg( -src2.x, -src2.y, -src2.z, -src2.w );
  629. return QuaternionsAreEqualInternal( src1, src2neg, flTolerance );
  630. }
  631. */
  632. inline const Quaternion GetNormalized( const Quaternion & q )
  633. {
  634. float flInv = 1.0f / sqrtf( q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w );
  635. return Quaternion( q.x * flInv, q.y * flInv, q.z * flInv, q.w * flInv );
  636. }
  637. inline const Quaternion AngleQuaternion( const QAngle& angles )
  638. {
  639. Quaternion qt;
  640. AngleQuaternion( angles, qt );
  641. return qt;
  642. }
  643. inline const Quaternion AngleQuaternion( RadianEuler const &angles )
  644. {
  645. Quaternion qt;
  646. AngleQuaternion( angles, qt );
  647. return qt;
  648. }
  649. inline Quaternion QuaternionFromPitchYawRoll( float flPitch, float flYaw, float flRoll )
  650. {
  651. QAngle ang( flPitch, flYaw, flRoll );
  652. Quaternion q;
  653. AngleQuaternion( ang, q );
  654. return q;
  655. }
  656. inline Quaternion QuaternionAddPitch( const Quaternion &q, float flPitch )
  657. {
  658. // FIXME: I know this can be made *tons* faster, but I just want to get something working quickly
  659. // that matches being able to add to the pitch of a QAngles so I can expose Quats to script/game code
  660. QAngle ang;
  661. QuaternionAngles( q, ang );
  662. ang[ PITCH ] += flPitch;
  663. Quaternion res;
  664. AngleQuaternion( ang, res );
  665. return res;
  666. }
  667. inline Quaternion QuaternionAddYaw( const Quaternion &q, float flYaw )
  668. {
  669. // FIXME: I know this can be made *tons* faster, but I just want to get something working quickly
  670. // that matches being able to add to the yaw of a QAngles so I can expose Quats to script/game code
  671. QAngle ang;
  672. QuaternionAngles( q, ang );
  673. ang[ YAW ] += flYaw;
  674. Quaternion res;
  675. AngleQuaternion( ang, res );
  676. return res;
  677. }
  678. inline Quaternion QuaternionAddRoll( const Quaternion &q, float flRoll )
  679. {
  680. // FIXME: I know this can be made *tons* faster, but I just want to get something working quickly
  681. // that matches being able to add to the roll of a QAngles so I can expose Quats to script/game code
  682. QAngle ang;
  683. QuaternionAngles( q, ang );
  684. ang[ ROLL ] += flRoll;
  685. Quaternion res;
  686. AngleQuaternion( ang, res );
  687. return res;
  688. }
  689. inline const Quaternion MatrixQuaternion( const matrix3x4_t &mat )
  690. {
  691. Quaternion tmp;
  692. MatrixQuaternion( mat, tmp );
  693. return tmp;
  694. }
  695. inline const Quaternion MatrixQuaternionFast( const matrix3x4_t &mat )
  696. {
  697. Quaternion tmp;
  698. MatrixQuaternionFast( mat, tmp );
  699. return tmp;
  700. }
  701. inline const matrix3x4_t QuaternionMatrix( const Quaternion &q )
  702. {
  703. matrix3x4_t mat;
  704. QuaternionMatrix( q, mat );
  705. return mat;
  706. }
  707. inline const matrix3x4_t QuaternionMatrix( const Quaternion &q, const Vector &pos )
  708. {
  709. matrix3x4_t mat;
  710. QuaternionMatrix( q, pos, mat );
  711. return mat;
  712. }
  713. //! Shortest-arc quaternion that rotates vector v1 into vector v2
  714. const Quaternion RotateBetween( const Vector& v1, const Vector& v2 );
  715. inline const Quaternion QuaternionConjugate( const Quaternion &p )
  716. {
  717. Quaternion q;
  718. QuaternionConjugate( p, q );
  719. return q;
  720. }
  721. inline const Quaternion QuaternionInvert( const Quaternion &p )
  722. {
  723. Quaternion q;
  724. QuaternionInvert( p, q );
  725. return q;
  726. }
  727. /// Actual quaternion multiplication; NOTE: QuaternionMult aligns quaternions first, so that q *
  728. /// conjugate(q) may be -1 instead of 1!
  729. inline const Quaternion operator * ( const Quaternion &p, const Quaternion &q )
  730. {
  731. Quaternion qt;
  732. qt.x = p.x * q.w + p.y * q.z - p.z * q.y + p.w * q.x;
  733. qt.y = -p.x * q.z + p.y * q.w + p.z * q.x + p.w * q.y;
  734. qt.z = p.x * q.y - p.y * q.x + p.z * q.w + p.w * q.z;
  735. qt.w = -p.x * q.x - p.y * q.y - p.z * q.z + p.w * q.w;
  736. return qt;
  737. }
  738. inline Quaternion& operator *= ( Quaternion &p, const Quaternion &q )
  739. {
  740. QuaternionMult( p, q, p );
  741. return p;
  742. }
  743. inline const matrix3x4_t ConcatTransforms( const matrix3x4_t &in1, const matrix3x4_t &in2 )
  744. {
  745. matrix3x4_t out;
  746. ConcatTransforms( in1, in2, out );
  747. return out;
  748. }
  749. inline const matrix3x4_t operator *( const matrix3x4_t &in1, const matrix3x4_t &in2 )
  750. {
  751. matrix3x4_t out;
  752. ConcatTransforms( in1, in2, out );
  753. return out;
  754. }
  755. inline const matrix3x4_t MatrixInvert( const matrix3x4_t &in )
  756. {
  757. matrix3x4_t out;
  758. ::MatrixInvert( in, out );
  759. return out;
  760. }
  761. inline const Vector MatrixGetColumn( const matrix3x4_t &in, MatrixAxisType_t nColumn )
  762. {
  763. return in.GetColumn( nColumn );
  764. }
  765. // A couple methods to find the dot product of a vector with a matrix row or column...
  766. inline float MatrixRowDotProduct( const matrix3x4_t &in1, int row, const Vector& in2 )
  767. {
  768. Assert( (row >= 0) && (row < 3) );
  769. return DotProduct( in1[row], in2.Base() );
  770. }
  771. inline float MatrixColumnDotProduct( const matrix3x4_t &in1, int col, const Vector& in2 )
  772. {
  773. Assert( (col >= 0) && (col < 4) );
  774. return in1[0][col] * in2[0] + in1[1][col] * in2[1] + in1[2][col] * in2[2];
  775. }
  776. int __cdecl BoxOnPlaneSide (const float *emins, const float *emaxs, const cplane_t *plane);
  777. inline float anglemod(float a)
  778. {
  779. a = (360.f/65536) * ((int)(a*(65536.f/360.0f)) & 65535);
  780. return a;
  781. }
  782. //// CLAMP
  783. #if defined(__cplusplus) && defined(PLATFORM_PPC)
  784. #ifdef _X360
  785. #define __fsels __fsel
  786. #endif
  787. template< >
  788. inline double clamp( double const &val, double const &minVal, double const &maxVal )
  789. {
  790. float diffmin = val - minVal;
  791. float diffmax = maxVal - val;
  792. float r;
  793. r = __fsel(diffmin, val, minVal);
  794. r = __fsel(diffmax, r, maxVal);
  795. return r;
  796. }
  797. template< >
  798. inline double clamp( double const &val, float const &minVal, float const &maxVal )
  799. {
  800. // these typecasts are actually free since all FPU regs are 64 bit on PPC anyway
  801. return clamp ( val, (double) minVal, (double) maxVal );
  802. }
  803. template< >
  804. inline double clamp( double const &val, float const &minVal, double const &maxVal )
  805. {
  806. return clamp ( val, (double) minVal, (double) maxVal );
  807. }
  808. template< >
  809. inline double clamp( double const &val, double const &minVal, float const &maxVal )
  810. {
  811. return clamp ( val, (double) minVal, (double) maxVal );
  812. }
  813. template< >
  814. inline float clamp( float const &val, float const &minVal, float const &maxVal )
  815. {
  816. float diffmin = val - minVal;
  817. float diffmax = maxVal - val;
  818. float r;
  819. r = __fsels(diffmin, val, minVal);
  820. r = __fsels(diffmax, r, maxVal);
  821. return r;
  822. }
  823. template< >
  824. inline float clamp( float const &val, double const &minVal, double const &maxVal )
  825. {
  826. float diffmin = val - minVal;
  827. float diffmax = maxVal - val;
  828. float r;
  829. r = __fsels(diffmin, val, minVal);
  830. r = __fsels(diffmax, r, maxVal);
  831. return r;
  832. }
  833. template< >
  834. inline float clamp( float const &val, double const &minVal, float const &maxVal )
  835. {
  836. return clamp ( val, (float) minVal, maxVal );
  837. }
  838. template< >
  839. inline float clamp( float const &val, float const &minVal, double const &maxVal )
  840. {
  841. return clamp ( val, minVal, (float) maxVal );
  842. }
  843. #endif
  844. // Remap a value in the range [A,B] to [C,D].
  845. inline float RemapVal( float val, float A, float B, float C, float D)
  846. {
  847. if ( A == B )
  848. return fsel( val - B , D , C );
  849. return C + (D - C) * (val - A) / (B - A);
  850. }
  851. inline float RemapValClamped( float val, float A, float B, float C, float D)
  852. {
  853. if ( A == B )
  854. return fsel( val - B , D , C );
  855. float cVal = (val - A) / (B - A);
  856. cVal = clamp<float>( cVal, 0.0f, 1.0f );
  857. return C + (D - C) * cVal;
  858. }
  859. // Returns A + (B-A)*flPercent.
  860. // float Lerp( float flPercent, float A, float B );
  861. template <class T>
  862. FORCEINLINE T Lerp( float flPercent, T const &A, T const &B )
  863. {
  864. return A + (B - A) * flPercent;
  865. }
  866. FORCEINLINE float Sqr( float f )
  867. {
  868. return f*f;
  869. }
  870. // 5-argument floating point linear interpolation.
  871. // FLerp(f1,f2,i1,i2,x)=
  872. // f1 at x=i1
  873. // f2 at x=i2
  874. // smooth lerp between f1 and f2 at x>i1 and x<i2
  875. // extrapolation for x<i1 or x>i2
  876. //
  877. // If you know a function f(x)'s value (f1) at position i1, and its value (f2) at position i2,
  878. // the function can be linearly interpolated with FLerp(f1,f2,i1,i2,x)
  879. // i2=i1 will cause a divide by zero.
  880. static inline float FLerp(float f1, float f2, float i1, float i2, float x)
  881. {
  882. return f1+(f2-f1)*(x-i1)/(i2-i1);
  883. }
  884. #ifndef VECTOR_NO_SLOW_OPERATIONS
  885. // YWB: Specialization for interpolating euler angles via quaternions...
  886. template<> FORCEINLINE QAngle Lerp<QAngle>( float flPercent, const QAngle& q1, const QAngle& q2 )
  887. {
  888. // Avoid precision errors
  889. if ( q1 == q2 )
  890. return q1;
  891. Quaternion src, dest;
  892. // Convert to quaternions
  893. AngleQuaternion( q1, src );
  894. AngleQuaternion( q2, dest );
  895. Quaternion result;
  896. // Slerp
  897. QuaternionSlerp( src, dest, flPercent, result );
  898. // Convert to euler
  899. QAngle output;
  900. QuaternionAngles( result, output );
  901. return output;
  902. }
  903. #else
  904. #pragma error
  905. // NOTE NOTE: I haven't tested this!! It may not work! Check out interpolatedvar.cpp in the client dll to try it
  906. template<> FORCEINLINE QAngleByValue Lerp<QAngleByValue>( float flPercent, const QAngleByValue& q1, const QAngleByValue& q2 )
  907. {
  908. // Avoid precision errors
  909. if ( q1 == q2 )
  910. return q1;
  911. Quaternion src, dest;
  912. // Convert to quaternions
  913. AngleQuaternion( q1, src );
  914. AngleQuaternion( q2, dest );
  915. Quaternion result;
  916. // Slerp
  917. QuaternionSlerp( src, dest, flPercent, result );
  918. // Convert to euler
  919. QAngleByValue output;
  920. QuaternionAngles( result, output );
  921. return output;
  922. }
  923. #endif // VECTOR_NO_SLOW_OPERATIONS
  924. // Swap two of anything.
  925. template <class T>
  926. FORCEINLINE void V_swap( T& x, T& y )
  927. {
  928. T temp = x;
  929. x = y;
  930. y = temp;
  931. }
  932. template <class T> FORCEINLINE T AVG(T a, T b)
  933. {
  934. return (a+b)/2;
  935. }
  936. // number of elements in an array of static size
  937. #define NELEMS(x) ((sizeof(x))/sizeof(x[0]))
  938. // XYZ macro, for printf type functions - ex printf("%f %f %f",XYZ(myvector));
  939. #define XYZ(v) (v).x,(v).y,(v).z
  940. inline float Sign( float x )
  941. {
  942. return fsel( x, 1.0f, -1.0f ); // x >= 0 ? 1.0f : -1.0f
  943. //return (x <0.0f) ? -1.0f : 1.0f;
  944. }
  945. //
  946. // Clamps the input integer to the given array bounds.
  947. // Equivalent to the following, but without using any branches:
  948. //
  949. // if( n < 0 ) return 0;
  950. // else if ( n > maxindex ) return maxindex;
  951. // else return n;
  952. //
  953. // This is not always a clear performance win, but when you have situations where a clamped
  954. // value is thrashing against a boundary this is a big win. (ie, valid, invalid, valid, invalid, ...)
  955. //
  956. // Note: This code has been run against all possible integers.
  957. //
  958. inline int ClampArrayBounds( int n, unsigned maxindex )
  959. {
  960. // mask is 0 if less than 4096, 0xFFFFFFFF if greater than
  961. unsigned int inrangemask = 0xFFFFFFFF + (((unsigned) n) > maxindex );
  962. unsigned int lessthan0mask = 0xFFFFFFFF + ( n >= 0 );
  963. // If the result was valid, set the result, (otherwise sets zero)
  964. int result = (inrangemask & n);
  965. // if the result was out of range or zero.
  966. result |= ((~inrangemask) & (~lessthan0mask)) & maxindex;
  967. return result;
  968. }
  969. // Turn a number "inside out".
  970. // See Recording Animation in Binary Order for Progressive Temporal Refinement
  971. // by Paul Heckbert from "Graphics Gems".
  972. //
  973. // If you want to iterate something from 0 to n, you can use this to iterate non-sequentially, in
  974. // such a way that you will start with widely separated values and then refine the gaps between
  975. // them, as you would for progressive refinement. This works with non-power of two ranges.
  976. int InsideOut( int nTotal, int nCounter );
  977. #define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
  978. (((p)->type < 3)? \
  979. ( \
  980. ((p)->dist <= (emins)[(p)->type])? \
  981. 1 \
  982. : \
  983. ( \
  984. ((p)->dist >= (emaxs)[(p)->type])?\
  985. 2 \
  986. : \
  987. 3 \
  988. ) \
  989. ) \
  990. : \
  991. BoxOnPlaneSide( (emins), (emaxs), (p)))
  992. //-----------------------------------------------------------------------------
  993. // FIXME: Vector versions.... the float versions will go away hopefully soon!
  994. //-----------------------------------------------------------------------------
  995. void AngleVectors (const QAngle& angles, Vector *forward);
  996. void AngleVectors (const QAngle& angles, Vector *forward, Vector *right, Vector *up);
  997. void AngleVectorsTranspose (const QAngle& angles, Vector *forward, Vector *right, Vector *up);
  998. void AngleVectorsFLU( const QAngle& angles, Vector *pForward, Vector *pLeft, Vector *pUp );
  999. void AngleMatrix (const QAngle &angles, matrix3x4_t &mat );
  1000. void AngleMatrix( const QAngle &angles, const Vector &position, matrix3x4_t &mat );
  1001. void AngleMatrix (const RadianEuler &angles, matrix3x4_t &mat );
  1002. void AngleMatrix( RadianEuler const &angles, const Vector &position, matrix3x4_t &mat );
  1003. void AngleIMatrix (const QAngle &angles, matrix3x4_t &mat );
  1004. void AngleIMatrix (const QAngle &angles, const Vector &position, matrix3x4_t &mat );
  1005. void AngleIMatrix (const RadianEuler &angles, matrix3x4_t &mat );
  1006. void VectorAngles( const Vector &forward, QAngle &angles );
  1007. void VectorAngles( const Vector &forward, const Vector &pseudoup, QAngle &angles );
  1008. void VectorMatrix( const Vector &forward, matrix3x4_t &mat );
  1009. void VectorVectors( const Vector &forward, Vector &right, Vector &up );
  1010. void SetIdentityMatrix( matrix3x4_t &mat );
  1011. void SetScaleMatrix( float x, float y, float z, matrix3x4_t &dst );
  1012. void MatrixBuildRotationAboutAxis( const Vector &vAxisOfRot, float angleDegrees, matrix3x4_t &dst );
  1013. inline bool MatrixIsIdentity( const matrix3x4_t &m )
  1014. {
  1015. return
  1016. m.m_flMatVal[0][0] == 1.0f && m.m_flMatVal[0][1] == 0.0f && m.m_flMatVal[0][2] == 0.0f && m.m_flMatVal[0][3] == 0.0f &&
  1017. m.m_flMatVal[1][0] == 0.0f && m.m_flMatVal[1][1] == 1.0f && m.m_flMatVal[1][2] == 0.0f && m.m_flMatVal[1][3] == 0.0f &&
  1018. m.m_flMatVal[2][0] == 0.0f && m.m_flMatVal[2][1] == 0.0f && m.m_flMatVal[2][2] == 1.0f && m.m_flMatVal[2][3] == 0.0f;
  1019. }
  1020. inline void SetScaleMatrix( float flScale, matrix3x4_t &dst )
  1021. {
  1022. SetScaleMatrix( flScale, flScale, flScale, dst );
  1023. }
  1024. inline void SetScaleMatrix( const Vector& scale, matrix3x4_t &dst )
  1025. {
  1026. SetScaleMatrix( scale.x, scale.y, scale.z, dst );
  1027. }
  1028. // Computes the inverse transpose
  1029. void MatrixTranspose( matrix3x4_t& mat );
  1030. void MatrixTranspose( const matrix3x4_t& src, matrix3x4_t& dst );
  1031. void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst );
  1032. inline void PositionMatrix( const Vector &position, matrix3x4_t &mat )
  1033. {
  1034. MatrixSetColumn( position, 3, mat );
  1035. }
  1036. inline void MatrixPosition( const matrix3x4_t &matrix, Vector &position )
  1037. {
  1038. position[0] = matrix[0][3];
  1039. position[1] = matrix[1][3];
  1040. position[2] = matrix[2][3];
  1041. }
  1042. inline void VectorRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out)
  1043. {
  1044. VectorRotate( &in1.x, in2, &out.x );
  1045. }
  1046. inline void VectorIRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out)
  1047. {
  1048. VectorIRotate( &in1.x, in2, &out.x );
  1049. }
  1050. inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles )
  1051. {
  1052. MatrixAngles( matrix, &angles.x );
  1053. }
  1054. inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles, Vector &position )
  1055. {
  1056. MatrixAngles( matrix, angles );
  1057. MatrixPosition( matrix, position );
  1058. }
  1059. inline void MatrixAngles( const matrix3x4_t &matrix, RadianEuler &angles )
  1060. {
  1061. MatrixAngles( matrix, &angles.x );
  1062. angles.Init( DEG2RAD( angles.z ), DEG2RAD( angles.x ), DEG2RAD( angles.y ) );
  1063. }
  1064. void MatrixAngles( const matrix3x4_t &mat, RadianEuler &angles, Vector &position );
  1065. void MatrixAngles( const matrix3x4_t &mat, Quaternion &q, Vector &position );
  1066. inline int VectorCompare (const Vector& v1, const Vector& v2)
  1067. {
  1068. return v1 == v2;
  1069. }
  1070. inline void VectorTransform (const Vector& in1, const matrix3x4_t &in2, Vector &out)
  1071. {
  1072. VectorTransform( &in1.x, in2, &out.x );
  1073. }
  1074. // MSVC folds the return value nicely and creates no temporaries on the stack,
  1075. // we need more experiments with different compilers and in different circumstances
  1076. inline const Vector VectorTransform( const Vector& in1, const matrix3x4_t &in2 )
  1077. {
  1078. Vector out;
  1079. VectorTransform( in1, in2, out );
  1080. return out;
  1081. }
  1082. inline const Vector VectorRotate( const Vector& in1, const matrix3x4_t &in2 )
  1083. {
  1084. Vector out;
  1085. VectorRotate( in1, in2, out );
  1086. return out;
  1087. }
  1088. inline void VectorITransform (const Vector& in1, const matrix3x4_t &in2, Vector &out)
  1089. {
  1090. VectorITransform( &in1.x, in2, &out.x );
  1091. }
  1092. inline const Vector VectorITransform( const Vector& in1, const matrix3x4_t &in2 )
  1093. {
  1094. Vector out;
  1095. VectorITransform( in1, in2, out );
  1096. return out;
  1097. }
  1098. /*
  1099. inline void DecomposeRotation( const matrix3x4_t &mat, Vector &out )
  1100. {
  1101. DecomposeRotation( mat, &out.x );
  1102. }
  1103. */
  1104. inline int BoxOnPlaneSide (const Vector& emins, const Vector& emaxs, const cplane_t *plane )
  1105. {
  1106. return BoxOnPlaneSide( &emins.x, &emaxs.x, plane );
  1107. }
  1108. inline void VectorFill(Vector& a, float b)
  1109. {
  1110. a[0]=a[1]=a[2]=b;
  1111. }
  1112. inline void VectorNegate(Vector& a)
  1113. {
  1114. a[0] = -a[0];
  1115. a[1] = -a[1];
  1116. a[2] = -a[2];
  1117. }
  1118. inline vec_t VectorAvg(Vector& a)
  1119. {
  1120. return ( a[0] + a[1] + a[2] ) / 3;
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // Box/plane test (slow version)
  1124. //-----------------------------------------------------------------------------
  1125. inline int FASTCALL BoxOnPlaneSide2 (const Vector& emins, const Vector& emaxs, const cplane_t *p, float tolerance = 0.f )
  1126. {
  1127. Vector corners[2];
  1128. if (p->normal[0] < 0)
  1129. {
  1130. corners[0][0] = emins[0];
  1131. corners[1][0] = emaxs[0];
  1132. }
  1133. else
  1134. {
  1135. corners[1][0] = emins[0];
  1136. corners[0][0] = emaxs[0];
  1137. }
  1138. if (p->normal[1] < 0)
  1139. {
  1140. corners[0][1] = emins[1];
  1141. corners[1][1] = emaxs[1];
  1142. }
  1143. else
  1144. {
  1145. corners[1][1] = emins[1];
  1146. corners[0][1] = emaxs[1];
  1147. }
  1148. if (p->normal[2] < 0)
  1149. {
  1150. corners[0][2] = emins[2];
  1151. corners[1][2] = emaxs[2];
  1152. }
  1153. else
  1154. {
  1155. corners[1][2] = emins[2];
  1156. corners[0][2] = emaxs[2];
  1157. }
  1158. int sides = 0;
  1159. float dist1 = DotProduct (p->normal, corners[0]) - p->dist;
  1160. if (dist1 >= tolerance)
  1161. sides = 1;
  1162. float dist2 = DotProduct (p->normal, corners[1]) - p->dist;
  1163. if (dist2 < -tolerance)
  1164. sides |= 2;
  1165. return sides;
  1166. }
  1167. //-----------------------------------------------------------------------------
  1168. // Helpers for bounding box construction
  1169. //-----------------------------------------------------------------------------
  1170. void ClearBounds (Vector& mins, Vector& maxs);
  1171. void AddPointToBounds (const Vector& v, Vector& mins, Vector& maxs);
  1172. //-----------------------------------------------------------------------------
  1173. // Ensures that the min and max bounds values are valid.
  1174. // (ClearBounds() sets min > max, which is clearly invalid.)
  1175. //-----------------------------------------------------------------------------
  1176. bool AreBoundsValid( const Vector &vMin, const Vector &vMax );
  1177. //-----------------------------------------------------------------------------
  1178. // Returns true if the provided point is in the AABB defined by vMin
  1179. // at the lower corner and vMax at the upper corner.
  1180. //-----------------------------------------------------------------------------
  1181. bool IsPointInBounds( const Vector &vPoint, const Vector &vMin, const Vector &vMax );
  1182. //
  1183. // COLORSPACE/GAMMA CONVERSION STUFF
  1184. //
  1185. void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright );
  1186. // convert texture to linear 0..1 value
  1187. inline float TexLightToLinear( int c, int exponent )
  1188. {
  1189. // On VS 2013 LTCG builds it is required that the array declaration be annotated with
  1190. // the same alignment requirements as the array definition.
  1191. extern ALIGN128 float power2_n[256];
  1192. Assert( exponent >= -128 && exponent <= 127 );
  1193. return ( float )c * power2_n[exponent+128];
  1194. }
  1195. // convert texture to linear 0..1 value
  1196. int LinearToTexture( float f );
  1197. // converts 0..1 linear value to screen gamma (0..255)
  1198. int LinearToScreenGamma( float f );
  1199. float TextureToLinear( int c );
  1200. // compressed color format
  1201. struct ColorRGBExp32
  1202. {
  1203. byte r, g, b;
  1204. signed char exponent;
  1205. };
  1206. void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out );
  1207. void VectorToColorRGBExp32( const Vector& v, ColorRGBExp32 &c );
  1208. // solve for "x" where "a x^2 + b x + c = 0", return true if solution exists
  1209. bool SolveQuadratic( float a, float b, float c, float &root1, float &root2 );
  1210. // solves for "a, b, c" where "a x^2 + b x + c = y", return true if solution exists
  1211. bool SolveInverseQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c );
  1212. // solves for a,b,c specified as above, except that it always creates a monotonically increasing or
  1213. // decreasing curve if the data is monotonically increasing or decreasing. In order to enforce the
  1214. // monoticity condition, it is possible that the resulting quadratic will only approximate the data
  1215. // instead of interpolating it. This code is not especially fast.
  1216. bool SolveInverseQuadraticMonotonic( float x1, float y1, float x2, float y2,
  1217. float x3, float y3, float &a, float &b, float &c );
  1218. // solves for "a, b, c" where "1/(a x^2 + b x + c ) = y", return true if solution exists
  1219. bool SolveInverseReciprocalQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c );
  1220. // rotate a vector around the Z axis (YAW)
  1221. void VectorYawRotate( const Vector& in, float flYaw, Vector &out);
  1222. // Bias takes an X value between 0 and 1 and returns another value between 0 and 1
  1223. // The curve is biased towards 0 or 1 based on biasAmt, which is between 0 and 1.
  1224. // Lower values of biasAmt bias the curve towards 0 and higher values bias it towards 1.
  1225. //
  1226. // For example, with biasAmt = 0.2, the curve looks like this:
  1227. //
  1228. // 1
  1229. // | *
  1230. // | *
  1231. // | *
  1232. // | **
  1233. // | **
  1234. // | ****
  1235. // |*********
  1236. // |___________________
  1237. // 0 1
  1238. //
  1239. //
  1240. // With biasAmt = 0.8, the curve looks like this:
  1241. //
  1242. // 1
  1243. // | **************
  1244. // | **
  1245. // | *
  1246. // | *
  1247. // |*
  1248. // |*
  1249. // |*
  1250. // |___________________
  1251. // 0 1
  1252. //
  1253. // With a biasAmt of 0.5, Bias returns X.
  1254. float Bias( float x, float biasAmt );
  1255. // Gain is similar to Bias, but biasAmt biases towards or away from 0.5.
  1256. // Lower bias values bias towards 0.5 and higher bias values bias away from it.
  1257. //
  1258. // For example, with biasAmt = 0.2, the curve looks like this:
  1259. //
  1260. // 1
  1261. // | *
  1262. // | *
  1263. // | **
  1264. // | ***************
  1265. // | **
  1266. // | *
  1267. // |*
  1268. // |___________________
  1269. // 0 1
  1270. //
  1271. //
  1272. // With biasAmt = 0.8, the curve looks like this:
  1273. //
  1274. // 1
  1275. // | *****
  1276. // | ***
  1277. // | *
  1278. // | *
  1279. // | *
  1280. // | ***
  1281. // |*****
  1282. // |___________________
  1283. // 0 1
  1284. float Gain( float x, float biasAmt );
  1285. // SmoothCurve maps a 0-1 value into another 0-1 value based on a cosine wave
  1286. // where the derivatives of the function at 0 and 1 (and 0.5) are 0. This is useful for
  1287. // any fadein/fadeout effect where it should start and end smoothly.
  1288. //
  1289. // The curve looks like this:
  1290. //
  1291. // 1
  1292. // | **
  1293. // | * *
  1294. // | * *
  1295. // | * *
  1296. // | * *
  1297. // | ** **
  1298. // |*** ***
  1299. // |___________________
  1300. // 0 1
  1301. //
  1302. float SmoothCurve( float x );
  1303. // This works like SmoothCurve, with two changes:
  1304. //
  1305. // 1. Instead of the curve peaking at 0.5, it will peak at flPeakPos.
  1306. // (So if you specify flPeakPos=0.2, then the peak will slide to the left).
  1307. //
  1308. // 2. flPeakSharpness is a 0-1 value controlling the sharpness of the peak.
  1309. // Low values blunt the peak and high values sharpen the peak.
  1310. float SmoothCurve_Tweak( float x, float flPeakPos=0.5, float flPeakSharpness=0.5 );
  1311. //float ExponentialDecay( float halflife, float dt );
  1312. //float ExponentialDecay( float decayTo, float decayTime, float dt );
  1313. // halflife is time for value to reach 50%
  1314. inline float ExponentialDecay( float halflife, float dt )
  1315. {
  1316. // log(0.5) == -0.69314718055994530941723212145818
  1317. return expf( -0.69314718f / halflife * dt);
  1318. }
  1319. // decayTo is factor the value should decay to in decayTime
  1320. inline float ExponentialDecay( float decayTo, float decayTime, float dt )
  1321. {
  1322. return expf( logf( decayTo ) / decayTime * dt);
  1323. }
  1324. // Get the integrated distanced traveled
  1325. // decayTo is factor the value should decay to in decayTime
  1326. // dt is the time relative to the last velocity update
  1327. inline float ExponentialDecayIntegral( float decayTo, float decayTime, float dt )
  1328. {
  1329. return (powf( decayTo, dt / decayTime) * decayTime - decayTime) / logf( decayTo );
  1330. }
  1331. // hermite basis function for smooth interpolation
  1332. // Similar to Gain() above, but very cheap to call
  1333. // value should be between 0 & 1 inclusive
  1334. inline float SimpleSpline( float value )
  1335. {
  1336. float valueSquared = value * value;
  1337. // Nice little ease-in, ease-out spline-like curve
  1338. return (3 * valueSquared - 2 * valueSquared * value);
  1339. }
  1340. // remaps a value in [startInterval, startInterval+rangeInterval] from linear to
  1341. // spline using SimpleSpline
  1342. inline float SimpleSplineRemapVal( float val, float A, float B, float C, float D)
  1343. {
  1344. if ( A == B )
  1345. return val >= B ? D : C;
  1346. float cVal = (val - A) / (B - A);
  1347. return C + (D - C) * SimpleSpline( cVal );
  1348. }
  1349. // remaps a value in [startInterval, startInterval+rangeInterval] from linear to
  1350. // spline using SimpleSpline
  1351. inline float SimpleSplineRemapValClamped( float val, float A, float B, float C, float D )
  1352. {
  1353. if ( A == B )
  1354. return val >= B ? D : C;
  1355. float cVal = (val - A) / (B - A);
  1356. cVal = clamp( cVal, 0.0f, 1.0f );
  1357. return C + (D - C) * SimpleSpline( cVal );
  1358. }
  1359. FORCEINLINE int RoundFloatToInt(float f)
  1360. {
  1361. #if defined( _X360 )
  1362. #ifdef Assert
  1363. Assert( IsFPUControlWordSet() );
  1364. #endif
  1365. union
  1366. {
  1367. double flResult;
  1368. int pResult[2];
  1369. };
  1370. flResult = __fctiw( f );
  1371. return pResult[1];
  1372. #elif defined ( _PS3 )
  1373. #if defined(__SPU__)
  1374. int nResult;
  1375. nResult = static_cast<int>(f);
  1376. return nResult;
  1377. #else
  1378. return __fctiw( f );
  1379. #endif
  1380. #else // !X360
  1381. int nResult;
  1382. #if defined( COMPILER_MSVC32 )
  1383. __asm
  1384. {
  1385. fld f
  1386. fistp nResult
  1387. }
  1388. #elif GNUC
  1389. __asm __volatile__ (
  1390. "fistpl %0;": "=m" (nResult): "t" (f) : "st"
  1391. );
  1392. #else
  1393. nResult = static_cast<int>(f);
  1394. #endif
  1395. return nResult;
  1396. #endif
  1397. }
  1398. FORCEINLINE unsigned char RoundFloatToByte(float f)
  1399. {
  1400. #if defined( _X360 )
  1401. #ifdef Assert
  1402. Assert( IsFPUControlWordSet() );
  1403. #endif
  1404. union
  1405. {
  1406. double flResult;
  1407. int pIntResult[2];
  1408. unsigned char pResult[8];
  1409. };
  1410. flResult = __fctiw( f );
  1411. #ifdef Assert
  1412. Assert( pIntResult[1] >= 0 && pIntResult[1] <= 255 );
  1413. #endif
  1414. return pResult[7];
  1415. #elif defined ( _PS3 )
  1416. #if defined(__SPU__)
  1417. int nResult;
  1418. nResult = static_cast<unsigned int> (f) & 0xff;
  1419. return nResult;
  1420. #else
  1421. return __fctiw( f );
  1422. #endif
  1423. #else // !X360
  1424. int nResult;
  1425. #if defined( COMPILER_MSVC32 )
  1426. __asm
  1427. {
  1428. fld f
  1429. fistp nResult
  1430. }
  1431. #elif GNUC
  1432. __asm __volatile__ (
  1433. "fistpl %0;": "=m" (nResult): "t" (f) : "st"
  1434. );
  1435. #else
  1436. nResult = static_cast<unsigned int> (f) & 0xff;
  1437. #endif
  1438. #ifdef Assert
  1439. Assert( nResult >= 0 && nResult <= 255 );
  1440. #endif
  1441. return nResult;
  1442. #endif
  1443. }
  1444. FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f)
  1445. {
  1446. #if defined( _X360 )
  1447. #ifdef Assert
  1448. Assert( IsFPUControlWordSet() );
  1449. #endif
  1450. union
  1451. {
  1452. double flResult;
  1453. int pIntResult[2];
  1454. unsigned long pResult[2];
  1455. };
  1456. flResult = __fctiw( f );
  1457. Assert( pIntResult[1] >= 0 );
  1458. return pResult[1];
  1459. #elif defined ( _PS3 )
  1460. #if defined(__SPU__)
  1461. return static_cast<unsigned long>(f);
  1462. #else
  1463. return __fctiw( f );
  1464. #endif
  1465. #else // !X360
  1466. #if defined( COMPILER_MSVC32 )
  1467. unsigned char nResult[8];
  1468. __asm
  1469. {
  1470. fld f
  1471. fistp qword ptr nResult
  1472. }
  1473. return *((unsigned long*)nResult);
  1474. #elif defined( COMPILER_GCC )
  1475. unsigned char nResult[8];
  1476. __asm __volatile__ (
  1477. "fistpl %0;": "=m" (nResult): "t" (f) : "st"
  1478. );
  1479. return *((unsigned long*)nResult);
  1480. #else
  1481. return static_cast<unsigned long>(f);
  1482. #endif
  1483. #endif
  1484. }
  1485. FORCEINLINE bool IsIntegralValue( float flValue, float flTolerance = 0.001f )
  1486. {
  1487. return fabs( RoundFloatToInt( flValue ) - flValue ) < flTolerance;
  1488. }
  1489. // Fast, accurate ftol:
  1490. FORCEINLINE int Float2Int( float a )
  1491. {
  1492. #if defined( _X360 )
  1493. union
  1494. {
  1495. double flResult;
  1496. int pResult[2];
  1497. };
  1498. flResult = __fctiwz( a );
  1499. return pResult[1];
  1500. #elif defined ( _PS3 )
  1501. #if defined(__SPU__)
  1502. int RetVal;
  1503. RetVal = static_cast<int>( a );
  1504. return RetVal;
  1505. #else
  1506. return __fctiwz( a );
  1507. #endif
  1508. #else // !X360
  1509. int RetVal;
  1510. #if defined( COMPILER_MSVC32 )
  1511. int CtrlwdHolder;
  1512. int CtrlwdSetter;
  1513. __asm
  1514. {
  1515. fld a // push 'a' onto the FP stack
  1516. fnstcw CtrlwdHolder // store FPU control word
  1517. movzx eax, CtrlwdHolder // move and zero extend word into eax
  1518. and eax, 0xFFFFF3FF // set all bits except rounding bits to 1
  1519. or eax, 0x00000C00 // set rounding mode bits to round towards zero
  1520. mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid!
  1521. fldcw CtrlwdSetter // Entering plaid!
  1522. fistp RetVal // Store and converted (to int) result
  1523. fldcw CtrlwdHolder // Restore control word
  1524. }
  1525. #else
  1526. RetVal = static_cast<int>( a );
  1527. #endif
  1528. return RetVal;
  1529. #endif
  1530. }
  1531. // Over 15x faster than: (int)floor(value)
  1532. inline int Floor2Int( float a )
  1533. {
  1534. int RetVal;
  1535. #if defined( PLATFORM_PPC )
  1536. RetVal = (int)floor( a );
  1537. #elif defined( COMPILER_MSVC32 )
  1538. int CtrlwdHolder;
  1539. int CtrlwdSetter;
  1540. __asm
  1541. {
  1542. fld a // push 'a' onto the FP stack
  1543. fnstcw CtrlwdHolder // store FPU control word
  1544. movzx eax, CtrlwdHolder // move and zero extend word into eax
  1545. and eax, 0xFFFFF3FF // set all bits except rounding bits to 1
  1546. or eax, 0x00000400 // set rounding mode bits to round down
  1547. mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid!
  1548. fldcw CtrlwdSetter // Entering plaid!
  1549. fistp RetVal // Store floored and converted (to int) result
  1550. fldcw CtrlwdHolder // Restore control word
  1551. }
  1552. #else
  1553. RetVal = static_cast<int>( floor(a) );
  1554. #endif
  1555. return RetVal;
  1556. }
  1557. //-----------------------------------------------------------------------------
  1558. // Fast color conversion from float to unsigned char
  1559. //-----------------------------------------------------------------------------
  1560. FORCEINLINE unsigned char FastFToC( float c )
  1561. {
  1562. volatile float dc;
  1563. // ieee trick
  1564. dc = c * 255.0f + (float)(1 << 23);
  1565. // return the lsb
  1566. #if defined( _X360 ) || defined( _PS3 )
  1567. return ((unsigned char*)&dc)[3];
  1568. #else
  1569. return *(unsigned char*)&dc;
  1570. #endif
  1571. }
  1572. //-----------------------------------------------------------------------------
  1573. // Purpose: Bound input float to .001 (millisecond) boundary
  1574. // Input : in -
  1575. // Output : inline float
  1576. //-----------------------------------------------------------------------------
  1577. inline float ClampToMsec( float in )
  1578. {
  1579. int msec = Floor2Int( in * 1000.0f + 0.5f );
  1580. return msec / 1000.0f;
  1581. }
  1582. // Over 15x faster than: (int)ceil(value)
  1583. inline int Ceil2Int( float a )
  1584. {
  1585. int RetVal;
  1586. #if defined( PLATFORM_PPC )
  1587. RetVal = (int)ceil( a );
  1588. #elif defined( COMPILER_MSVC32 )
  1589. int CtrlwdHolder;
  1590. int CtrlwdSetter;
  1591. __asm
  1592. {
  1593. fld a // push 'a' onto the FP stack
  1594. fnstcw CtrlwdHolder // store FPU control word
  1595. movzx eax, CtrlwdHolder // move and zero extend word into eax
  1596. and eax, 0xFFFFF3FF // set all bits except rounding bits to 1
  1597. or eax, 0x00000800 // set rounding mode bits to round down
  1598. mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid!
  1599. fldcw CtrlwdSetter // Entering plaid!
  1600. fistp RetVal // Store floored and converted (to int) result
  1601. fldcw CtrlwdHolder // Restore control word
  1602. }
  1603. #else
  1604. RetVal = static_cast<int>( ceil(a) );
  1605. #endif
  1606. return RetVal;
  1607. }
  1608. // Regular signed area of triangle
  1609. #define TriArea2D( A, B, C ) \
  1610. ( 0.5f * ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) )
  1611. // This version doesn't premultiply by 0.5f, so it's the area of the rectangle instead
  1612. #define TriArea2DTimesTwo( A, B, C ) \
  1613. ( ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) )
  1614. // Get the barycentric coordinates of "pt" in triangle [A,B,C].
  1615. inline void GetBarycentricCoords2D(
  1616. Vector2D const &A,
  1617. Vector2D const &B,
  1618. Vector2D const &C,
  1619. Vector2D const &pt,
  1620. float bcCoords[3] )
  1621. {
  1622. // Note, because to top and bottom are both x2, the issue washes out in the composite
  1623. float invTriArea = 1.0f / TriArea2DTimesTwo( A, B, C );
  1624. // NOTE: We assume here that the lightmap coordinate vertices go counterclockwise.
  1625. // If not, TriArea2D() is negated so this works out right.
  1626. bcCoords[0] = TriArea2DTimesTwo( B, C, pt ) * invTriArea;
  1627. bcCoords[1] = TriArea2DTimesTwo( C, A, pt ) * invTriArea;
  1628. bcCoords[2] = TriArea2DTimesTwo( A, B, pt ) * invTriArea;
  1629. }
  1630. // Return true of the sphere might touch the box (the sphere is actually treated
  1631. // like a box itself, so this may return true if the sphere's bounding box touches
  1632. // a corner of the box but the sphere itself doesn't).
  1633. inline bool QuickBoxSphereTest(
  1634. const Vector& vOrigin,
  1635. float flRadius,
  1636. const Vector& bbMin,
  1637. const Vector& bbMax )
  1638. {
  1639. return vOrigin.x - flRadius < bbMax.x && vOrigin.x + flRadius > bbMin.x &&
  1640. vOrigin.y - flRadius < bbMax.y && vOrigin.y + flRadius > bbMin.y &&
  1641. vOrigin.z - flRadius < bbMax.z && vOrigin.z + flRadius > bbMin.z;
  1642. }
  1643. // Return true of the boxes intersect (but not if they just touch).
  1644. inline bool QuickBoxIntersectTest(
  1645. const Vector& vBox1Min,
  1646. const Vector& vBox1Max,
  1647. const Vector& vBox2Min,
  1648. const Vector& vBox2Max )
  1649. {
  1650. return
  1651. vBox1Min.x < vBox2Max.x && vBox1Max.x > vBox2Min.x &&
  1652. vBox1Min.y < vBox2Max.y && vBox1Max.y > vBox2Min.y &&
  1653. vBox1Min.z < vBox2Max.z && vBox1Max.z > vBox2Min.z;
  1654. }
  1655. extern float GammaToLinearFullRange( float gamma );
  1656. extern float LinearToGammaFullRange( float linear );
  1657. extern float GammaToLinear( float gamma );
  1658. extern float LinearToGamma( float linear );
  1659. extern float SrgbGammaToLinear( float flSrgbGammaValue );
  1660. extern float SrgbLinearToGamma( float flLinearValue );
  1661. extern float X360GammaToLinear( float fl360GammaValue );
  1662. extern float X360LinearToGamma( float flLinearValue );
  1663. extern float SrgbGammaTo360Gamma( float flSrgbGammaValue );
  1664. // linear (0..4) to screen corrected vertex space (0..1?)
  1665. FORCEINLINE float LinearToVertexLight( float f )
  1666. {
  1667. extern float lineartovertex[4096];
  1668. // Gotta clamp before the multiply; could overflow...
  1669. // assume 0..4 range
  1670. int i = RoundFloatToInt( f * 1024.f );
  1671. // Presumably the comman case will be not to clamp, so check that first:
  1672. if( (unsigned)i > 4095 )
  1673. {
  1674. if ( i < 0 )
  1675. i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream
  1676. else
  1677. i = 4095;
  1678. }
  1679. return lineartovertex[i];
  1680. }
  1681. FORCEINLINE unsigned char LinearToLightmap( float f )
  1682. {
  1683. extern unsigned char lineartolightmap[4096];
  1684. // Gotta clamp before the multiply; could overflow...
  1685. int i = RoundFloatToInt( f * 1024.f ); // assume 0..4 range
  1686. // Presumably the comman case will be not to clamp, so check that first:
  1687. if ( (unsigned)i > 4095 )
  1688. {
  1689. if ( i < 0 )
  1690. i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream
  1691. else
  1692. i = 4095;
  1693. }
  1694. return lineartolightmap[i];
  1695. }
  1696. FORCEINLINE void ColorClamp( Vector& color )
  1697. {
  1698. float maxc = MAX( color.x, MAX( color.y, color.z ) );
  1699. if ( maxc > 1.0f )
  1700. {
  1701. float ooMax = 1.0f / maxc;
  1702. color.x *= ooMax;
  1703. color.y *= ooMax;
  1704. color.z *= ooMax;
  1705. }
  1706. if ( color[0] < 0.f ) color[0] = 0.f;
  1707. if ( color[1] < 0.f ) color[1] = 0.f;
  1708. if ( color[2] < 0.f ) color[2] = 0.f;
  1709. }
  1710. inline void ColorClampTruncate( Vector& color )
  1711. {
  1712. if (color[0] > 1.0f) color[0] = 1.0f; else if (color[0] < 0.0f) color[0] = 0.0f;
  1713. if (color[1] > 1.0f) color[1] = 1.0f; else if (color[1] < 0.0f) color[1] = 0.0f;
  1714. if (color[2] > 1.0f) color[2] = 1.0f; else if (color[2] < 0.0f) color[2] = 0.0f;
  1715. }
  1716. // Interpolate a Catmull-Rom spline.
  1717. // t is a [0,1] value and interpolates a curve between p2 and p3.
  1718. void Catmull_Rom_Spline(
  1719. const Vector &p1,
  1720. const Vector &p2,
  1721. const Vector &p3,
  1722. const Vector &p4,
  1723. float t,
  1724. Vector &output );
  1725. // Interpolate a Catmull-Rom spline.
  1726. // Returns the tangent of the point at t of the spline
  1727. void Catmull_Rom_Spline_Tangent(
  1728. const Vector &p1,
  1729. const Vector &p2,
  1730. const Vector &p3,
  1731. const Vector &p4,
  1732. float t,
  1733. Vector &output );
  1734. // area under the curve [0..t]
  1735. void Catmull_Rom_Spline_Integral(
  1736. const Vector &p1,
  1737. const Vector &p2,
  1738. const Vector &p3,
  1739. const Vector &p4,
  1740. float t,
  1741. Vector& output );
  1742. // area under the curve [0..1]
  1743. void Catmull_Rom_Spline_Integral(
  1744. const Vector &p1,
  1745. const Vector &p2,
  1746. const Vector &p3,
  1747. const Vector &p4,
  1748. Vector& output );
  1749. // Interpolate a Catmull-Rom spline.
  1750. // Normalize p2->p1 and p3->p4 to be the same length as p2->p3
  1751. void Catmull_Rom_Spline_Normalize(
  1752. const Vector &p1,
  1753. const Vector &p2,
  1754. const Vector &p3,
  1755. const Vector &p4,
  1756. float t,
  1757. Vector &output );
  1758. // area under the curve [0..t]
  1759. // Normalize p2->p1 and p3->p4 to be the same length as p2->p3
  1760. void Catmull_Rom_Spline_Integral_Normalize(
  1761. const Vector &p1,
  1762. const Vector &p2,
  1763. const Vector &p3,
  1764. const Vector &p4,
  1765. float t,
  1766. Vector& output );
  1767. // Interpolate a Catmull-Rom spline.
  1768. // Normalize p2.x->p1.x and p3.x->p4.x to be the same length as p2.x->p3.x
  1769. void Catmull_Rom_Spline_NormalizeX(
  1770. const Vector &p1,
  1771. const Vector &p2,
  1772. const Vector &p3,
  1773. const Vector &p4,
  1774. float t,
  1775. Vector &output );
  1776. // area under the curve [0..t]
  1777. void Catmull_Rom_Spline_NormalizeX(
  1778. const Vector &p1,
  1779. const Vector &p2,
  1780. const Vector &p3,
  1781. const Vector &p4,
  1782. float t,
  1783. Vector& output );
  1784. // Interpolate a Hermite spline.
  1785. // t is a [0,1] value and interpolates a curve between p1 and p2 with the deltas d1 and d2.
  1786. void Hermite_Spline(
  1787. const Vector &p1,
  1788. const Vector &p2,
  1789. const Vector &d1,
  1790. const Vector &d2,
  1791. float t,
  1792. Vector& output );
  1793. float Hermite_Spline(
  1794. float p1,
  1795. float p2,
  1796. float d1,
  1797. float d2,
  1798. float t );
  1799. // t is a [0,1] value and interpolates a curve between p1 and p2 with the slopes p0->p1 and p1->p2
  1800. void Hermite_Spline(
  1801. const Vector &p0,
  1802. const Vector &p1,
  1803. const Vector &p2,
  1804. float t,
  1805. Vector& output );
  1806. float Hermite_Spline(
  1807. float p0,
  1808. float p1,
  1809. float p2,
  1810. float t );
  1811. void Hermite_SplineBasis( float t, float basis[] );
  1812. void Hermite_Spline(
  1813. const Quaternion &q0,
  1814. const Quaternion &q1,
  1815. const Quaternion &q2,
  1816. float t,
  1817. Quaternion &output );
  1818. // See http://en.wikipedia.org/wiki/Kochanek-Bartels_curves
  1819. //
  1820. // Tension: -1 = Round -> 1 = Tight
  1821. // Bias: -1 = Pre-shoot (bias left) -> 1 = Post-shoot (bias right)
  1822. // Continuity: -1 = Box corners -> 1 = Inverted corners
  1823. //
  1824. // If T=B=C=0 it's the same matrix as Catmull-Rom.
  1825. // If T=1 & B=C=0 it's the same as Cubic.
  1826. // If T=B=0 & C=-1 it's just linear interpolation
  1827. //
  1828. // See http://news.povray.org/povray.binaries.tutorials/attachment/%[email protected]%3E/Splines.bas.txt
  1829. // for example code and descriptions of various spline types...
  1830. //
  1831. void Kochanek_Bartels_Spline(
  1832. float tension,
  1833. float bias,
  1834. float continuity,
  1835. const Vector &p1,
  1836. const Vector &p2,
  1837. const Vector &p3,
  1838. const Vector &p4,
  1839. float t,
  1840. Vector& output );
  1841. void Kochanek_Bartels_Spline_NormalizeX(
  1842. float tension,
  1843. float bias,
  1844. float continuity,
  1845. const Vector &p1,
  1846. const Vector &p2,
  1847. const Vector &p3,
  1848. const Vector &p4,
  1849. float t,
  1850. Vector& output );
  1851. // See link at Kochanek_Bartels_Spline for info on the basis matrix used
  1852. void Cubic_Spline(
  1853. const Vector &p1,
  1854. const Vector &p2,
  1855. const Vector &p3,
  1856. const Vector &p4,
  1857. float t,
  1858. Vector& output );
  1859. void Cubic_Spline_NormalizeX(
  1860. const Vector &p1,
  1861. const Vector &p2,
  1862. const Vector &p3,
  1863. const Vector &p4,
  1864. float t,
  1865. Vector& output );
  1866. // See link at Kochanek_Bartels_Spline for info on the basis matrix used
  1867. void BSpline(
  1868. const Vector &p1,
  1869. const Vector &p2,
  1870. const Vector &p3,
  1871. const Vector &p4,
  1872. float t,
  1873. Vector& output );
  1874. void BSpline_NormalizeX(
  1875. const Vector &p1,
  1876. const Vector &p2,
  1877. const Vector &p3,
  1878. const Vector &p4,
  1879. float t,
  1880. Vector& output );
  1881. // See link at Kochanek_Bartels_Spline for info on the basis matrix used
  1882. void Parabolic_Spline(
  1883. const Vector &p1,
  1884. const Vector &p2,
  1885. const Vector &p3,
  1886. const Vector &p4,
  1887. float t,
  1888. Vector& output );
  1889. void Parabolic_Spline_NormalizeX(
  1890. const Vector &p1,
  1891. const Vector &p2,
  1892. const Vector &p3,
  1893. const Vector &p4,
  1894. float t,
  1895. Vector& output );
  1896. // Evaluate the cubic Bernstein basis for the input parametric coordinate.
  1897. // Output is the coefficient for that basis polynomial.
  1898. float CubicBasis0( float t );
  1899. float CubicBasis1( float t );
  1900. float CubicBasis2( float t );
  1901. float CubicBasis3( float t );
  1902. // quintic interpolating polynomial from Perlin.
  1903. // 0->0, 1->1, smooth-in between with smooth tangents
  1904. inline float QuinticInterpolatingPolynomial(float t)
  1905. {
  1906. // 6t^5-15t^4+10t^3
  1907. return t * t * t *( t * ( t* 6.0 - 15.0 ) + 10.0 );
  1908. }
  1909. // given a table of sorted tabulated positions, return the two indices and blendfactor to linear
  1910. // interpolate. Does a search. Can be used to find the blend value to interpolate between
  1911. // keyframes.
  1912. void GetInterpolationData( float const *pKnotPositions,
  1913. float const *pKnotValues,
  1914. int nNumValuesinList,
  1915. int nInterpolationRange,
  1916. float flPositionToInterpolateAt,
  1917. bool bWrap,
  1918. float *pValueA,
  1919. float *pValueB,
  1920. float *pInterpolationValue);
  1921. float RangeCompressor( float flValue, float flMin, float flMax, float flBase );
  1922. // Get the minimum distance from vOrigin to the bounding box defined by [mins,maxs]
  1923. // using voronoi regions.
  1924. // 0 is returned if the origin is inside the box.
  1925. float CalcSqrDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point );
  1926. void CalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut );
  1927. void CalcSqrDistAndClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut, float &distSqrOut );
  1928. inline float CalcDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point )
  1929. {
  1930. float flDistSqr = CalcSqrDistanceToAABB( mins, maxs, point );
  1931. return sqrt(flDistSqr);
  1932. }
  1933. // Get the closest point from P to the (infinite) line through vLineA and vLineB and
  1934. // calculate the shortest distance from P to the line.
  1935. // If you pass in a value for t, it will tell you the t for (A + (B-A)t) to get the closest point.
  1936. // If the closest point lies on the segment between A and B, then 0 <= t <= 1.
  1937. void CalcClosestPointOnLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 );
  1938. float CalcDistanceToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1939. float CalcDistanceSqrToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1940. // The same three functions as above, except now the line is closed between A and B.
  1941. void CalcClosestPointOnLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 );
  1942. float CalcDistanceToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1943. float CalcDistanceSqrToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
  1944. // A function to compute the closes line segment connnection two lines (or false if the lines are parallel, etc.)
  1945. bool CalcLineToLineIntersectionSegment(
  1946. const Vector& p1,const Vector& p2,const Vector& p3,const Vector& p4,Vector *s1,Vector *s2,
  1947. float *t1, float *t2 );
  1948. // The above functions in 2D
  1949. void CalcClosestPointOnLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 );
  1950. float CalcDistanceToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1951. float CalcDistanceSqrToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1952. void CalcClosestPointOnLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 );
  1953. float CalcDistanceToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1954. float CalcDistanceSqrToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
  1955. // Init the mathlib
  1956. 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 );
  1957. bool MathLib_MMXEnabled( void );
  1958. bool MathLib_SSEEnabled( void );
  1959. bool MathLib_SSE2Enabled( void );
  1960. inline float Approach( float target, float value, float speed );
  1961. float ApproachAngle( float target, float value, float speed );
  1962. float AngleDiff( float destAngle, float srcAngle );
  1963. float AngleDistance( float next, float cur );
  1964. float AngleNormalize( float angle );
  1965. // ensure that 0 <= angle <= 360
  1966. float AngleNormalizePositive( float angle );
  1967. bool AnglesAreEqual( float a, float b, float tolerance = 0.0f );
  1968. void RotationDeltaAxisAngle( const QAngle &srcAngles, const QAngle &destAngles, Vector &deltaAxis, float &deltaAngle );
  1969. void RotationDelta( const QAngle &srcAngles, const QAngle &destAngles, QAngle *out );
  1970. //-----------------------------------------------------------------------------
  1971. // Clips a line segment such that only the portion in the positive half-space
  1972. // of the plane remains. If the segment is entirely clipped, the vectors
  1973. // are set to vec3_invalid (all components are FLT_MAX).
  1974. //
  1975. // flBias is added to the dot product with the normal. A positive bias
  1976. // results in a more inclusive positive half-space, while a negative bias
  1977. // results in a more exclusive positive half-space.
  1978. //-----------------------------------------------------------------------------
  1979. void ClipLineSegmentToPlane( const Vector &vNormal, const Vector &vPlanePoint, Vector *p1, Vector *p2, float flBias = 0.0f );
  1980. void ComputeTrianglePlane( const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept );
  1981. int PolyFromPlane( Vector *pOutVerts, const Vector& normal, float dist, float fHalfScale = 9000.0f );
  1982. void PolyFromPlane_SIMD( fltx4 *pOutVerts, const fltx4 & plane, float fHalfScale = 9000.0f );
  1983. int ClipPolyToPlane( Vector *inVerts, int vertCount, Vector *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon = 0.1f );
  1984. int ClipPolyToPlane_SIMD( fltx4 *pInVerts, int vertCount, fltx4 *pOutVerts, const fltx4& plane, float fOnPlaneEpsilon = 0.1f );
  1985. int ClipPolyToPlane_Precise( double *inVerts, int vertCount, double *outVerts, const double *normal, double dist, double fOnPlaneEpsilon = 0.1 );
  1986. float TetrahedronVolume( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3 );
  1987. float TriangleArea( const Vector &p0, const Vector &p1, const Vector &p2 );
  1988. /// return surface area of an AABB
  1989. FORCEINLINE float BoxSurfaceArea( Vector const &vecBoxMin, Vector const &vecBoxMax )
  1990. {
  1991. Vector boxdim = vecBoxMax - vecBoxMin;
  1992. return 2.0 * ( ( boxdim[0] * boxdim[2] ) + ( boxdim[0] * boxdim[1] ) + ( boxdim[1] * boxdim[2] ) );
  1993. }
  1994. //-----------------------------------------------------------------------------
  1995. // Computes a reasonable tangent space for a triangle
  1996. //-----------------------------------------------------------------------------
  1997. void CalcTriangleTangentSpace( const Vector &p0, const Vector &p1, const Vector &p2,
  1998. const Vector2D &t0, const Vector2D &t1, const Vector2D& t2,
  1999. Vector &sVect, Vector &tVect );
  2000. //-----------------------------------------------------------------------------
  2001. // Transforms a AABB into another space; which will inherently grow the box.
  2002. //-----------------------------------------------------------------------------
  2003. void TransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  2004. //-----------------------------------------------------------------------------
  2005. // Uses the inverse transform of in1
  2006. //-----------------------------------------------------------------------------
  2007. void ITransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  2008. //-----------------------------------------------------------------------------
  2009. // Rotates a AABB into another space; which will inherently grow the box.
  2010. // (same as TransformAABB, but doesn't take the translation into account)
  2011. //-----------------------------------------------------------------------------
  2012. void RotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  2013. //-----------------------------------------------------------------------------
  2014. // Uses the inverse transform of in1
  2015. //-----------------------------------------------------------------------------
  2016. void IRotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );
  2017. //-----------------------------------------------------------------------------
  2018. // Transform a plane
  2019. //-----------------------------------------------------------------------------
  2020. inline void MatrixTransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane )
  2021. {
  2022. // What we want to do is the following:
  2023. // 1) transform the normal into the new space.
  2024. // 2) Determine a point on the old plane given by plane dist * plane normal
  2025. // 3) Transform that point into the new space
  2026. // 4) Plane dist = DotProduct( new normal, new point )
  2027. // An optimized version, which works if the plane is orthogonal.
  2028. // 1) Transform the normal into the new space
  2029. // 2) Realize that transforming the old plane point into the new space
  2030. // is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ]
  2031. // where d = old plane dist, n' = transformed normal, Tn = translational component of transform
  2032. // 3) Compute the new plane dist using the dot product of the normal result of #2
  2033. // For a correct result, this should be an inverse-transpose matrix
  2034. // but that only matters if there are nonuniform scale or skew factors in this matrix.
  2035. VectorRotate( inPlane.normal, src, outPlane.normal );
  2036. outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
  2037. outPlane.dist += outPlane.normal.x * src[0][3] + outPlane.normal.y * src[1][3] + outPlane.normal.z * src[2][3];
  2038. }
  2039. inline void MatrixITransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane )
  2040. {
  2041. // The trick here is that Tn = translational component of transform,
  2042. // but for an inverse transform, Tn = - R^-1 * T
  2043. Vector vecTranslation;
  2044. MatrixGetColumn( src, 3, vecTranslation );
  2045. Vector vecInvTranslation;
  2046. VectorIRotate( vecTranslation, src, vecInvTranslation );
  2047. VectorIRotate( inPlane.normal, src, outPlane.normal );
  2048. outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
  2049. outPlane.dist -= outPlane.normal.x * vecInvTranslation[0] + outPlane.normal.y * vecInvTranslation[1] + outPlane.normal.z * vecInvTranslation[2];
  2050. }
  2051. int CeilPow2( int in );
  2052. int FloorPow2( int in );
  2053. FORCEINLINE float * UnpackNormal_HEND3N( const unsigned int *pPackedNormal, float *pNormal )
  2054. {
  2055. int temp[3];
  2056. temp[0] = ((*pPackedNormal >> 0L) & 0x7ff);
  2057. if ( temp[0] & 0x400 )
  2058. {
  2059. temp[0] = 2048 - temp[0];
  2060. }
  2061. temp[1] = ((*pPackedNormal >> 11L) & 0x7ff);
  2062. if ( temp[1] & 0x400 )
  2063. {
  2064. temp[1] = 2048 - temp[1];
  2065. }
  2066. temp[2] = ((*pPackedNormal >> 22L) & 0x3ff);
  2067. if ( temp[2] & 0x200 )
  2068. {
  2069. temp[2] = 1024 - temp[2];
  2070. }
  2071. pNormal[0] = (float)temp[0] * 1.0f/1023.0f;
  2072. pNormal[1] = (float)temp[1] * 1.0f/1023.0f;
  2073. pNormal[2] = (float)temp[2] * 1.0f/511.0f;
  2074. return pNormal;
  2075. }
  2076. FORCEINLINE unsigned int * PackNormal_HEND3N( const float *pNormal, unsigned int *pPackedNormal )
  2077. {
  2078. int temp[3];
  2079. temp[0] = Float2Int( pNormal[0] * 1023.0f );
  2080. temp[1] = Float2Int( pNormal[1] * 1023.0f );
  2081. temp[2] = Float2Int( pNormal[2] * 511.0f );
  2082. // the normal is out of bounds, determine the source and fix
  2083. // clamping would be even more of a slowdown here
  2084. Assert( temp[0] >= -1023 && temp[0] <= 1023 );
  2085. Assert( temp[1] >= -1023 && temp[1] <= 1023 );
  2086. Assert( temp[2] >= -511 && temp[2] <= 511 );
  2087. *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) |
  2088. ( ( temp[1] & 0x7ff ) << 11L ) |
  2089. ( ( temp[0] & 0x7ff ) << 0L );
  2090. return pPackedNormal;
  2091. }
  2092. FORCEINLINE unsigned int * PackNormal_HEND3N( float nx, float ny, float nz, unsigned int *pPackedNormal )
  2093. {
  2094. int temp[3];
  2095. temp[0] = Float2Int( nx * 1023.0f );
  2096. temp[1] = Float2Int( ny * 1023.0f );
  2097. temp[2] = Float2Int( nz * 511.0f );
  2098. // the normal is out of bounds, determine the source and fix
  2099. // clamping would be even more of a slowdown here
  2100. Assert( temp[0] >= -1023 && temp[0] <= 1023 );
  2101. Assert( temp[1] >= -1023 && temp[1] <= 1023 );
  2102. Assert( temp[2] >= -511 && temp[2] <= 511 );
  2103. *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) |
  2104. ( ( temp[1] & 0x7ff ) << 11L ) |
  2105. ( ( temp[0] & 0x7ff ) << 0L );
  2106. return pPackedNormal;
  2107. }
  2108. FORCEINLINE float * UnpackNormal_SHORT2( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE )
  2109. {
  2110. // Unpacks from Jason's 2-short format (fills in a 4th binormal-sign (+1/-1) value, if this is a tangent vector)
  2111. // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits)
  2112. short iX = (*pPackedNormal & 0x0000FFFF);
  2113. short iY = (*pPackedNormal & 0xFFFF0000) >> 16;
  2114. float zSign = +1;
  2115. if ( iX < 0 )
  2116. {
  2117. zSign = -1;
  2118. iX = -iX;
  2119. }
  2120. float tSign = +1;
  2121. if ( iY < 0 )
  2122. {
  2123. tSign = -1;
  2124. iY = -iY;
  2125. }
  2126. pNormal[0] = ( iX - 16384.0f ) / 16384.0f;
  2127. pNormal[1] = ( iY - 16384.0f ) / 16384.0f;
  2128. float mag = ( pNormal[0]*pNormal[0] + pNormal[1]*pNormal[1] );
  2129. if ( mag > 1.0f )
  2130. {
  2131. mag = 1.0f;
  2132. }
  2133. pNormal[2] = zSign*sqrtf( 1.0f - mag );
  2134. if ( bIsTangent )
  2135. {
  2136. pNormal[3] = tSign;
  2137. }
  2138. return pNormal;
  2139. }
  2140. FORCEINLINE unsigned int * PackNormal_SHORT2( float nx, float ny, float nz, unsigned int *pPackedNormal, float binormalSign = +1.0f )
  2141. {
  2142. // Pack a vector (ASSUMED TO BE NORMALIZED) into Jason's 4-byte (SHORT2) format.
  2143. // This simply reconstructs Z from X & Y. It uses the sign bits of the X & Y coords
  2144. // to reconstruct the sign of Z and, if this is a tangent vector, the sign of the
  2145. // binormal (this is needed because tangent/binormal vectors are supposed to follow
  2146. // UV gradients, but shaders reconstruct the binormal from the tangent and normal
  2147. // assuming that they form a right-handed basis).
  2148. nx += 1; // [-1,+1] -> [0,2]
  2149. ny += 1;
  2150. nx *= 16384.0f; // [ 0, 2] -> [0,32768]
  2151. ny *= 16384.0f;
  2152. // '0' and '32768' values are invalid encodings
  2153. nx = MAX( nx, 1.0f ); // Make sure there are no zero values
  2154. ny = MAX( ny, 1.0f );
  2155. nx = MIN( nx, 32767.0f ); // Make sure there are no 32768 values
  2156. ny = MIN( ny, 32767.0f );
  2157. if ( nz < 0.0f )
  2158. nx = -nx; // Set the sign bit for z
  2159. ny *= binormalSign; // Set the sign bit for the binormal (use when encoding a tangent vector)
  2160. // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits), also use Float2Int()
  2161. short sX = (short)nx; // signed short [1,32767]
  2162. short sY = (short)ny;
  2163. *pPackedNormal = ( sX & 0x0000FFFF ) | ( sY << 16 ); // NOTE: The mask is necessary (if sX is negative and cast to an int...)
  2164. return pPackedNormal;
  2165. }
  2166. FORCEINLINE unsigned int * PackNormal_SHORT2( const float *pNormal, unsigned int *pPackedNormal, float binormalSign = +1.0f )
  2167. {
  2168. return PackNormal_SHORT2( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, binormalSign );
  2169. }
  2170. // Unpacks a UBYTE4 normal (for a tangent, the result's fourth component receives the binormal 'sign')
  2171. FORCEINLINE float * UnpackNormal_UBYTE4( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE )
  2172. {
  2173. unsigned char cX, cY;
  2174. if ( bIsTangent )
  2175. {
  2176. cX = *pPackedNormal >> 16; // Unpack Z
  2177. cY = *pPackedNormal >> 24; // Unpack W
  2178. }
  2179. else
  2180. {
  2181. cX = *pPackedNormal >> 0; // Unpack X
  2182. cY = *pPackedNormal >> 8; // Unpack Y
  2183. }
  2184. float x = cX - 128.0f;
  2185. float y = cY - 128.0f;
  2186. float z;
  2187. float zSignBit = x < 0 ? 1.0f : 0.0f; // z and t negative bits (like slt asm instruction)
  2188. float tSignBit = y < 0 ? 1.0f : 0.0f;
  2189. float zSign = -( 2*zSignBit - 1 ); // z and t signs
  2190. float tSign = -( 2*tSignBit - 1 );
  2191. x = x*zSign - zSignBit; // 0..127
  2192. y = y*tSign - tSignBit;
  2193. x = x - 64; // -64..63
  2194. y = y - 64;
  2195. float xSignBit = x < 0 ? 1.0f : 0.0f; // x and y negative bits (like slt asm instruction)
  2196. float ySignBit = y < 0 ? 1.0f : 0.0f;
  2197. float xSign = -( 2*xSignBit - 1 ); // x and y signs
  2198. float ySign = -( 2*ySignBit - 1 );
  2199. x = ( x*xSign - xSignBit ) / 63.0f; // 0..1 range
  2200. y = ( y*ySign - ySignBit ) / 63.0f;
  2201. z = 1.0f - x - y;
  2202. float oolen = 1.0f / sqrt( x*x + y*y + z*z ); // Normalize and
  2203. x *= oolen * xSign; // Recover signs
  2204. y *= oolen * ySign;
  2205. z *= oolen * zSign;
  2206. pNormal[0] = x;
  2207. pNormal[1] = y;
  2208. pNormal[2] = z;
  2209. if ( bIsTangent )
  2210. {
  2211. pNormal[3] = tSign;
  2212. }
  2213. return pNormal;
  2214. }
  2215. //////////////////////////////////////////////////////////////////////////////
  2216. // See: http://www.oroboro.com/rafael/docserv.php/index/programming/article/unitv2
  2217. //
  2218. // UBYTE4 encoding, using per-octant projection onto x+y+z=1
  2219. // Assume input vector is already unit length
  2220. //
  2221. // binormalSign specifies 'sign' of binormal, stored in t sign bit of tangent
  2222. // (lets the shader know whether norm/tan/bin form a right-handed basis)
  2223. //
  2224. // bIsTangent is used to specify which WORD of the output to store the data
  2225. // The expected usage is to call once with the normal and once with
  2226. // the tangent and binormal sign flag, bitwise OR'ing the returned DWORDs
  2227. FORCEINLINE unsigned int * PackNormal_UBYTE4( float nx, float ny, float nz, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f )
  2228. {
  2229. float xSign = nx < 0.0f ? -1.0f : 1.0f; // -1 or 1 sign
  2230. float ySign = ny < 0.0f ? -1.0f : 1.0f;
  2231. float zSign = nz < 0.0f ? -1.0f : 1.0f;
  2232. float tSign = binormalSign;
  2233. Assert( ( binormalSign == +1.0f ) || ( binormalSign == -1.0f ) );
  2234. float xSignBit = 0.5f*( 1 - xSign ); // [-1,+1] -> [1,0]
  2235. float ySignBit = 0.5f*( 1 - ySign ); // 1 is negative bit (like slt instruction)
  2236. float zSignBit = 0.5f*( 1 - zSign );
  2237. float tSignBit = 0.5f*( 1 - binormalSign );
  2238. float absX = xSign*nx; // 0..1 range (abs)
  2239. float absY = ySign*ny;
  2240. float absZ = zSign*nz;
  2241. float xbits = absX / ( absX + absY + absZ ); // Project onto x+y+z=1 plane
  2242. float ybits = absY / ( absX + absY + absZ );
  2243. xbits *= 63; // 0..63
  2244. ybits *= 63;
  2245. xbits = xbits * xSign - xSignBit; // -64..63 range
  2246. ybits = ybits * ySign - ySignBit;
  2247. xbits += 64.0f; // 0..127 range
  2248. ybits += 64.0f;
  2249. xbits = xbits * zSign - zSignBit; // Negate based on z and t
  2250. ybits = ybits * tSign - tSignBit; // -128..127 range
  2251. xbits += 128.0f; // 0..255 range
  2252. ybits += 128.0f;
  2253. unsigned char cX = (unsigned char) xbits;
  2254. unsigned char cY = (unsigned char) ybits;
  2255. if ( !bIsTangent )
  2256. *pPackedNormal = (cX << 0) | (cY << 8); // xy for normal
  2257. else
  2258. *pPackedNormal = (cX << 16) | (cY << 24); // zw for tangent
  2259. return pPackedNormal;
  2260. }
  2261. FORCEINLINE unsigned int * PackNormal_UBYTE4( const float *pNormal, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f )
  2262. {
  2263. return PackNormal_UBYTE4( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, bIsTangent, binormalSign );
  2264. }
  2265. FORCEINLINE void RGB2YUV( int &nR, int &nG, int &nB, float &fY, float &fU, float &fV, bool bApplySaturationCurve )
  2266. {
  2267. // YUV conversion:
  2268. // |Y| | 0.299f 0.587f 0.114f | |R|
  2269. // |U| = | -0.14713f -0.28886f 0.436f | x |G|
  2270. // |V| | 0.615f -0.51499f -0.10001f | |B|
  2271. //
  2272. // The coefficients in the first row sum to one, whereas the 2nd and 3rd rows each sum to zero (UV (0,0) means greyscale).
  2273. // Ranges are Y [0,1], U [-0.436,+0.436] and V [-0.615,+0.615].
  2274. // We scale and offset to [0,1] and allow the caller to round as they please.
  2275. fY = ( 0.29900f*nR + 0.58700f*nG + 0.11400f*nB ) / 255;
  2276. fU = ( -0.14713f*nR + -0.28886f*nG + 0.43600f*nB )*( 0.5f / 0.436f ) / 255 + 0.5f;
  2277. fV = ( 0.61500f*nR + -0.51499f*nG + -0.10001f*nB )*( 0.5f / 0.615f ) / 255 + 0.5f;
  2278. if ( bApplySaturationCurve )
  2279. {
  2280. // Apply a curve to saturation, and snap-to-grey for low saturations
  2281. const float SNAP_TO_GREY = 0;//0.0125f; Disabled, saturation curve seems sufficient
  2282. float dX, dY, sat, scale;
  2283. dX = 2*( fU - 0.5f );
  2284. dY = 2*( fV - 0.5f );
  2285. sat = sqrtf( dX*dX + dY*dY );
  2286. sat = clamp( ( sat*( 1 + SNAP_TO_GREY ) - SNAP_TO_GREY ), 0, 1 );
  2287. scale = ( sat == 0 ) ? 0 : MIN( ( sqrtf( sat ) / sat ), 4.0f );
  2288. fU = 0.5f + scale*( fU - 0.5f );
  2289. fV = 0.5f + scale*( fV - 0.5f );
  2290. }
  2291. }
  2292. #ifdef _X360
  2293. // Used for direct CPU access to VB data on 360 (used by shaderapi, studiorender and engine)
  2294. struct VBCPU_AccessInfo_t
  2295. {
  2296. // Points to the GPU data pointer in the CVertexBuffer struct (VB data can be relocated during level transitions)
  2297. const byte **ppBaseAddress;
  2298. // pBaseAddress should be computed from ppBaseAddress immediately before use
  2299. const byte *pBaseAddress;
  2300. int nStride;
  2301. int nPositionOffset;
  2302. int nTexCoord0_Offset;
  2303. int nNormalOffset;
  2304. int nBoneIndexOffset;
  2305. int nBoneWeightOffset;
  2306. int nCompressionType;
  2307. // TODO: if needed, add colour and tangents
  2308. };
  2309. #endif
  2310. //-----------------------------------------------------------------------------
  2311. // Convert RGB to HSV
  2312. //-----------------------------------------------------------------------------
  2313. void RGBtoHSV( const Vector &rgb, Vector &hsv );
  2314. //-----------------------------------------------------------------------------
  2315. // Convert HSV to RGB
  2316. //-----------------------------------------------------------------------------
  2317. void HSVtoRGB( const Vector &hsv, Vector &rgb );
  2318. //-----------------------------------------------------------------------------
  2319. // Fast version of pow and log
  2320. //-----------------------------------------------------------------------------
  2321. #ifndef _PS3 // these actually aren't fast (or correct) on the PS3
  2322. float FastLog2(float i); // log2( i )
  2323. float FastPow2(float i); // 2^i
  2324. float FastPow(float a, float b); // a^b
  2325. float FastPow10( float i ); // 10^i
  2326. #else
  2327. inline float FastLog2(float i) {return logbf(i);} // log2( i )
  2328. inline float FastPow2(float i) {return exp2f(i);} // 2^i
  2329. inline float FastPow(float a, float b) {return powf(a,b);} // a^b
  2330. #define LOGBASE2OF10 3.3219280948873623478703194294893901758648313930
  2331. inline float FastPow10( float i ) { return exp2f( i * LOGBASE2OF10 ); } // 10^i, transform to base two, so log2(10^y) = y log2(10) . log2(10) = 3.3219280948873623478703194294893901758648313930
  2332. #endif
  2333. //-----------------------------------------------------------------------------
  2334. // For testing float equality
  2335. //-----------------------------------------------------------------------------
  2336. inline bool CloseEnough( float a, float b, float epsilon = EQUAL_EPSILON )
  2337. {
  2338. return fabs( a - b ) <= epsilon;
  2339. }
  2340. inline bool CloseEnough( const Vector &a, const Vector &b, float epsilon = EQUAL_EPSILON )
  2341. {
  2342. return fabs( a.x - b.x ) <= epsilon &&
  2343. fabs( a.y - b.y ) <= epsilon &&
  2344. fabs( a.z - b.z ) <= epsilon;
  2345. }
  2346. // Fast compare
  2347. // maxUlps is the maximum error in terms of Units in the Last Place. This
  2348. // specifies how big an error we are willing to accept in terms of the value
  2349. // of the least significant digit of the floating point number�s
  2350. // representation. maxUlps can also be interpreted in terms of how many
  2351. // representable floats we are willing to accept between A and B.
  2352. // This function will allow maxUlps-1 floats between A and B.
  2353. bool AlmostEqual(float a, float b, int maxUlps = 10);
  2354. inline bool AlmostEqual( const Vector &a, const Vector &b, int maxUlps = 10)
  2355. {
  2356. return AlmostEqual( a.x, b.x, maxUlps ) &&
  2357. AlmostEqual( a.y, b.y, maxUlps ) &&
  2358. AlmostEqual( a.z, b.z, maxUlps );
  2359. }
  2360. inline Vector Approach( Vector target, Vector value, float speed )
  2361. {
  2362. Vector diff = (target - value);
  2363. float delta = diff.Length();
  2364. if ( delta > speed )
  2365. value += diff.Normalized() * speed;
  2366. else if ( delta < -speed )
  2367. value -= diff.Normalized() * speed;
  2368. else
  2369. value = target;
  2370. return value;
  2371. }
  2372. inline float Approach( float target, float value, float speed )
  2373. {
  2374. float delta = target - value;
  2375. #if defined(_X360) || defined( _PS3 ) // use conditional move for speed on 360
  2376. return fsel( delta-speed, // delta >= speed ?
  2377. value + speed, // if delta == speed, then value + speed == value + delta == target
  2378. fsel( (-speed) - delta, // delta <= -speed
  2379. value - speed,
  2380. target )
  2381. ); // delta < speed && delta > -speed
  2382. #else
  2383. if ( delta > speed )
  2384. value += speed;
  2385. else if ( delta < -speed )
  2386. value -= speed;
  2387. else
  2388. value = target;
  2389. return value;
  2390. #endif
  2391. }
  2392. // return a 0..1 value based on the position of x between edge0 and edge1
  2393. inline float smoothstep_bounds(float edge0, float edge1, float x)
  2394. {
  2395. x = clamp((x - edge0)/(edge1 - edge0),0,1);
  2396. return x*x*(3 - 2*x);
  2397. }
  2398. // return a value between edge0 and edge1 based on the 0..1 value of x
  2399. inline float interpstep(float edge0, float edge1, float x)
  2400. {
  2401. return edge0 + (x * ( edge1 - edge0 ));
  2402. }
  2403. // on PPC we can do this truncate without converting to int
  2404. #if defined(_X360) || defined(_PS3)
  2405. inline double TruncateFloatToIntAsFloat( double flVal )
  2406. {
  2407. #if defined(_X360)
  2408. double flIntFormat = __fctiwz( flVal );
  2409. return __fcfid( flIntFormat );
  2410. #elif defined(_PS3)
  2411. #if defined(__SPU__)
  2412. int iVal = int(flVal);
  2413. return static_cast<double>(iVal);
  2414. #else
  2415. double flIntFormat = __builtin_fctiwz( flVal );
  2416. return __builtin_fcfid( flIntFormat );
  2417. #endif
  2418. #endif
  2419. }
  2420. #endif
  2421. inline double SubtractIntegerPart( double flVal )
  2422. {
  2423. #if defined(_X360) || defined(_PS3)
  2424. return flVal - TruncateFloatToIntAsFloat(flVal);
  2425. #else
  2426. return flVal - int(flVal);
  2427. #endif
  2428. }
  2429. inline void matrix3x4_t::InitFromQAngles( const QAngle &angles, const Vector &vPosition )
  2430. {
  2431. AngleMatrix( angles, vPosition, *this );
  2432. }
  2433. inline void matrix3x4_t::InitFromQAngles( const QAngle &angles ) { InitFromQAngles( angles, vec3_origin ); }
  2434. inline void matrix3x4_t::InitFromRadianEuler( const RadianEuler &angles, const Vector &vPosition )
  2435. {
  2436. AngleMatrix( angles, vPosition, *this );
  2437. }
  2438. inline void matrix3x4_t::InitFromRadianEuler( const RadianEuler &angles ) { InitFromRadianEuler( angles, vec3_origin ); }
  2439. inline void matrix3x4_t::InitFromQuaternion( const Quaternion &orientation, const Vector &vPosition )
  2440. {
  2441. QuaternionMatrix( orientation, vPosition, *this );
  2442. }
  2443. inline void matrix3x4_t::InitFromDiagonal( const Vector &vDiagonal )
  2444. {
  2445. SetToIdentity();
  2446. m_flMatVal[ 0 ][ 0 ] = vDiagonal.x;
  2447. m_flMatVal[ 1 ][ 1 ] = vDiagonal.y;
  2448. m_flMatVal[ 2 ][ 2 ] = vDiagonal.z;
  2449. }
  2450. inline void matrix3x4_t::InitFromQuaternion( const Quaternion &orientation ) { InitFromQuaternion( orientation, vec3_origin ); }
  2451. inline Quaternion matrix3x4_t::ToQuaternion() const
  2452. {
  2453. return MatrixQuaternion( *this );
  2454. }
  2455. inline QAngle matrix3x4_t::ToQAngle() const
  2456. {
  2457. QAngle tmp;
  2458. MatrixAngles( *this, tmp );
  2459. return tmp;
  2460. }
  2461. inline void matrix3x4_t::SetToIdentity()
  2462. {
  2463. SetIdentityMatrix( *this );
  2464. }
  2465. inline bool matrix3x4_t::IsEqualTo( const matrix3x4_t &other, float flTolerance ) const
  2466. {
  2467. return MatricesAreEqual( *this, other, flTolerance );
  2468. }
  2469. inline void matrix3x4_t::GetBasisVectorsFLU( Vector *pForward, Vector *pLeft, Vector *pUp ) const
  2470. {
  2471. return MatrixVectorsFLU( *this, pForward, pLeft, pUp );
  2472. }
  2473. inline Vector matrix3x4_t::TransformVector( const Vector &v0 ) const
  2474. {
  2475. return VectorTransform( v0, *this );
  2476. }
  2477. inline Vector matrix3x4_t::RotateVector( const Vector &v0 ) const
  2478. {
  2479. return VectorRotate( v0, *this );
  2480. }
  2481. inline Vector matrix3x4_t::TransformVectorByInverse( const Vector &v0 ) const
  2482. {
  2483. return VectorITransform( v0, *this );
  2484. }
  2485. inline Vector matrix3x4_t::RotateVectorByInverse( const Vector &v0 ) const
  2486. {
  2487. Vector tmp;
  2488. VectorIRotate( v0, *this, tmp );
  2489. return tmp;
  2490. }
  2491. inline Vector matrix3x4_t::RotateExtents( const Vector &vBoxExtents ) const
  2492. {
  2493. return Vector( DotProductAbs( vBoxExtents, m_flMatVal[ 0 ] ), DotProductAbs( vBoxExtents, m_flMatVal[ 1 ] ), DotProductAbs( vBoxExtents, m_flMatVal[ 2 ] ) );
  2494. }
  2495. inline Vector matrix3x4_t::GetColumn( MatrixAxisType_t nColumn ) const
  2496. {
  2497. return Vector( m_flMatVal[ 0 ][ nColumn ], m_flMatVal[ 1 ][ nColumn ], m_flMatVal[ 2 ][ nColumn ] );
  2498. }
  2499. inline void matrix3x4_t::SetColumn( const Vector &vColumn, MatrixAxisType_t nColumn )
  2500. {
  2501. m_flMatVal[ 0 ][ nColumn ] = vColumn.x;
  2502. m_flMatVal[ 1 ][ nColumn ] = vColumn.y;
  2503. m_flMatVal[ 2 ][ nColumn ] = vColumn.z;
  2504. }
  2505. inline void matrix3x4_t::InverseTR( matrix3x4_t &out ) const
  2506. {
  2507. ::MatrixInvert( *this, out );
  2508. }
  2509. inline matrix3x4_t matrix3x4_t::InverseTR() const
  2510. {
  2511. matrix3x4_t out;
  2512. ::MatrixInvert( *this, out );
  2513. return out;
  2514. }
  2515. inline void matrix3x4_t::TransformAABB( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const
  2516. {
  2517. ::TransformAABB( *this, vecMinsIn, vecMaxsIn, vecMinsOut, vecMaxsOut );
  2518. }
  2519. inline void matrix3x4_t::TransformAABBByInverse( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const
  2520. {
  2521. ::ITransformAABB( *this, vecMinsIn, vecMaxsIn, vecMinsOut, vecMaxsOut );
  2522. }
  2523. inline void matrix3x4_t::RotateAABB( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const
  2524. {
  2525. ::RotateAABB( *this, vecMinsIn, vecMaxsIn, vecMinsOut, vecMaxsOut );
  2526. }
  2527. inline void matrix3x4_t::RotateAABBByInverse( const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ) const
  2528. {
  2529. ::IRotateAABB( *this, vecMinsIn, vecMaxsIn, vecMinsOut, vecMaxsOut );
  2530. }
  2531. inline void matrix3x4_t::TransformPlane( const cplane_t &inPlane, cplane_t &outPlane ) const
  2532. {
  2533. ::MatrixTransformPlane( *this, inPlane, outPlane );
  2534. }
  2535. inline void matrix3x4_t::TransformPlaneByInverse( const cplane_t &inPlane, cplane_t &outPlane ) const
  2536. {
  2537. ::MatrixITransformPlane( *this, inPlane, outPlane );
  2538. }
  2539. inline float matrix3x4_t::GetOrthogonalityError() const
  2540. {
  2541. return
  2542. fabsf( m_flMatVal[ 0 ][ 0 ] * m_flMatVal[ 0 ][ 1 ] + m_flMatVal[ 1 ][ 0 ] * m_flMatVal[ 1 ][ 1 ] + m_flMatVal[ 2 ][ 0 ] * m_flMatVal[ 2 ][ 1 ] ) +
  2543. fabsf( m_flMatVal[ 0 ][ 1 ] * m_flMatVal[ 0 ][ 2 ] + m_flMatVal[ 1 ][ 1 ] * m_flMatVal[ 1 ][ 2 ] + m_flMatVal[ 2 ][ 1 ] * m_flMatVal[ 2 ][ 2 ] ) +
  2544. fabsf( m_flMatVal[ 0 ][ 2 ] * m_flMatVal[ 0 ][ 0 ] + m_flMatVal[ 1 ][ 2 ] * m_flMatVal[ 1 ][ 0 ] + m_flMatVal[ 2 ][ 2 ] * m_flMatVal[ 2 ][ 0 ] );
  2545. }
  2546. inline matrix3x4_t Quaternion::ToMatrix() const
  2547. {
  2548. matrix3x4_t mat;
  2549. mat.InitFromQuaternion( *this );
  2550. return mat;
  2551. }
  2552. inline matrix3x4_t QAngle::ToMatrix() const
  2553. {
  2554. matrix3x4_t mat;
  2555. AngleMatrix( *this, mat );
  2556. return mat;
  2557. }
  2558. inline Quaternion QAngle::ToQuaternion() const
  2559. {
  2560. return AngleQuaternion( *this );
  2561. }
  2562. inline float matrix3x4_t::GetDeterminant() const
  2563. {
  2564. return
  2565. m_flMatVal[ 0 ][ 0 ] * ( m_flMatVal[ 1 ][ 1 ] * m_flMatVal[ 2 ][ 2 ] - m_flMatVal[ 2 ][ 1 ] * m_flMatVal[ 1 ][ 2 ] )
  2566. - m_flMatVal[ 0 ][ 1 ] * ( m_flMatVal[ 1 ][ 0 ] * m_flMatVal[ 2 ][ 2 ] - m_flMatVal[ 1 ][ 2 ] * m_flMatVal[ 2 ][ 0 ] )
  2567. + m_flMatVal[ 0 ][ 2 ] * ( m_flMatVal[ 1 ][ 0 ] * m_flMatVal[ 2 ][ 1 ] - m_flMatVal[ 1 ][ 1 ] * m_flMatVal[ 2 ][ 0 ] );
  2568. }
  2569. inline float GetRelativeDifferenceSqr( const Vector &a, const Vector &b )
  2570. {
  2571. return ( a - b ).LengthSqr() / Max( 1.0f, Max( a.LengthSqr(), b.LengthSqr() ) );
  2572. }
  2573. inline float GetRelativeDifference( const Vector &a, const Vector &b )
  2574. {
  2575. return sqrtf( GetRelativeDifferenceSqr( a, b ) );
  2576. }
  2577. // a good measure of relative error between two TR matrices, perhaps with a reasonable scale
  2578. inline float GetRelativeDifference( const matrix3x4_t &a, const matrix3x4_t &b )
  2579. {
  2580. return sqrtf( Max( Max( GetRelativeDifferenceSqr( a.GetColumn( X_AXIS ), b.GetColumn( X_AXIS ) ),
  2581. GetRelativeDifferenceSqr( a.GetColumn( Y_AXIS ), b.GetColumn( Y_AXIS ) ) ),
  2582. Max( GetRelativeDifferenceSqr( a.GetColumn( Z_AXIS ), b.GetColumn( Z_AXIS ) ),
  2583. GetRelativeDifferenceSqr( a.GetOrigin(), b.GetOrigin() ) )
  2584. )
  2585. );
  2586. }
  2587. inline float matrix3x4_t::GetSylvestersCriterion()const
  2588. {
  2589. // http://en.wikipedia.org/wiki/Sylvester%27s_criterion
  2590. float flDet1 = m_flMatVal[ 0 ][ 0 ];
  2591. float flDet2 = m_flMatVal[ 0 ][ 0 ] * m_flMatVal[ 1 ][ 1 ] - m_flMatVal[ 1 ][ 0 ] * m_flMatVal[ 0 ][ 1 ];
  2592. float flDet3 = GetDeterminant();
  2593. return MIN( MIN( flDet1, flDet2 ), flDet3 );
  2594. }
  2595. // Generate the corner points of a box:
  2596. // +y _+z
  2597. // ^ /|
  2598. // | /
  2599. // | 3---7
  2600. // /| /|
  2601. // / | / |
  2602. // 2---6 |
  2603. // | 1|--5
  2604. // | / | /
  2605. // |/ |/
  2606. // 0---4 --> +x
  2607. //
  2608. void PointsFromBox( const Vector &mins, const Vector &maxs, Vector *points );
  2609. void BuildTransformedBox( Vector *v2, Vector const &bbmin, Vector const &bbmax, const matrix3x4_t& m );
  2610. #endif // MATH_BASE_H