Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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