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.

517 lines
11 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Math functions specific to the editor.
  4. //
  5. //=============================================================================//
  6. #include "hammer_mathlib.h"
  7. #include <string.h>
  8. #include <Windows.h>
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include <tier0/memdbgon.h>
  11. // provide implementation for mathlib Sys_Error()
  12. extern void Error(char* fmt, ...);
  13. extern "C" void Sys_Error( char *error, ... )
  14. {
  15. Error( "%s", error );
  16. }
  17. static int s_BoxFaces[6][3] =
  18. {
  19. { 0, 4, 2 },
  20. { 4, 5, 6 },
  21. { 5, 1, 7 },
  22. { 1, 0, 3 },
  23. { 2, 6, 3 },
  24. { 5, 4, 1 },
  25. };
  26. void polyMake( float x1, float y1, float x2, float y2, int npoints, float start_ang, Vector *pmPoints )
  27. {
  28. int point;
  29. double angle = start_ang, angle_delta = 360.0 / (double) npoints;
  30. double xrad = (x2-x1) / 2, yrad = (y2-y1) / 2;
  31. // make centerpoint for polygon:
  32. float xCenter = x1 + xrad;
  33. float yCenter = y1 + yrad;
  34. for( point = 0; point < npoints; point++, angle += angle_delta )
  35. {
  36. if( angle > 360 )
  37. angle -= 360;
  38. pmPoints[point][0] = rint(xCenter + (sin(DEG2RAD(angle)) * (float)xrad));
  39. pmPoints[point][1] = rint(yCenter + (cos(DEG2RAD(angle)) * (float)yrad));
  40. }
  41. pmPoints[point][0] = pmPoints[0][0];
  42. pmPoints[point][1] = pmPoints[0][1];
  43. }
  44. float fixang(float a)
  45. {
  46. if(a < 0.0)
  47. return a+360.0;
  48. if(a > 359.9)
  49. return a-360.0;
  50. return a;
  51. }
  52. float lineangle(float x1, float y1, float x2, float y2)
  53. {
  54. float x, y;
  55. float rvl;
  56. x = x2 - x1;
  57. y = y2 - y1;
  58. if(!x && !y)
  59. return 0.0;
  60. rvl = RAD2DEG(atan2( y, x ));
  61. return (rvl);
  62. }
  63. #if !defined(_MSC_VER) || _MSC_VER < 1800
  64. // This C99 function exists in VS 2013's math.h but are not currently available elsewhere.
  65. float rint(float f)
  66. {
  67. if (f > 0.0f) {
  68. return (float) floor(f + 0.5f);
  69. } else if (f < 0.0f) {
  70. return (float) ceil(f - 0.5f);
  71. } else
  72. return 0.0f;
  73. }
  74. #endif
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Builds the matrix for a counterclockwise rotation about an arbitrary axis.
  77. //
  78. // | ax2 + (1 - ax2)cosQ axay(1 - cosQ) - azsinQ azax(1 - cosQ) + aysinQ |
  79. // Ra(Q) = | axay(1 - cosQ) + azsinQ ay2 + (1 - ay2)cosQ ayaz(1 - cosQ) - axsinQ |
  80. // | azax(1 - cosQ) - aysinQ ayaz(1 - cosQ) + axsinQ az2 + (1 - az2)cosQ |
  81. //
  82. // Input : Matrix -
  83. // Axis -
  84. // fAngle -
  85. //-----------------------------------------------------------------------------
  86. void AxisAngleMatrix(VMatrix& Matrix, const Vector& Axis, float fAngle)
  87. {
  88. float fRadians;
  89. float fAxisXSquared;
  90. float fAxisYSquared;
  91. float fAxisZSquared;
  92. float fSin;
  93. float fCos;
  94. fRadians = fAngle * M_PI / 180.0;
  95. fSin = sin(fRadians);
  96. fCos = cos(fRadians);
  97. fAxisXSquared = Axis[0] * Axis[0];
  98. fAxisYSquared = Axis[1] * Axis[1];
  99. fAxisZSquared = Axis[2] * Axis[2];
  100. // Column 0:
  101. Matrix[0][0] = fAxisXSquared + (1 - fAxisXSquared) * fCos;
  102. Matrix[1][0] = Axis[0] * Axis[1] * (1 - fCos) + Axis[2] * fSin;
  103. Matrix[2][0] = Axis[2] * Axis[0] * (1 - fCos) - Axis[1] * fSin;
  104. Matrix[3][0] = 0;
  105. // Column 1:
  106. Matrix[0][1] = Axis[0] * Axis[1] * (1 - fCos) - Axis[2] * fSin;
  107. Matrix[1][1] = fAxisYSquared + (1 - fAxisYSquared) * fCos;
  108. Matrix[2][1] = Axis[1] * Axis[2] * (1 - fCos) + Axis[0] * fSin;
  109. Matrix[3][1] = 0;
  110. // Column 2:
  111. Matrix[0][2] = Axis[2] * Axis[0] * (1 - fCos) + Axis[1] * fSin;
  112. Matrix[1][2] = Axis[1] * Axis[2] * (1 - fCos) - Axis[0] * fSin;
  113. Matrix[2][2] = fAxisZSquared + (1 - fAxisZSquared) * fCos;
  114. Matrix[3][2] = 0;
  115. // Column 3:
  116. Matrix[0][3] = 0;
  117. Matrix[1][3] = 0;
  118. Matrix[2][3] = 0;
  119. Matrix[3][3] = 1;
  120. }
  121. void RotateAroundAxis(VMatrix& Matrix, float fDegrees, int nAxis)
  122. {
  123. int a,b;
  124. if ( fDegrees == 0 )
  125. return;
  126. if ( nAxis == 0 )
  127. {
  128. a=1; b=2;
  129. }
  130. else if ( nAxis == 1)
  131. {
  132. a=0;b=2;
  133. }
  134. else
  135. {
  136. a=0; b=1;
  137. }
  138. float fRadians = DEG2RAD(fDegrees);
  139. float fSin = (float)sin(fRadians);
  140. float fCos = (float)cos(fRadians);
  141. if ( nAxis == 1 )
  142. fSin = -fSin;
  143. float Temp0a = Matrix[0][a] * fCos + Matrix[0][b] * fSin;
  144. float Temp1a = Matrix[1][a] * fCos + Matrix[1][b] * fSin;
  145. float Temp2a = Matrix[2][a] * fCos + Matrix[2][b] * fSin;
  146. float Temp3a = Matrix[3][a] * fCos + Matrix[3][b] * fSin;
  147. if ( nAxis == 1 )
  148. fSin = -fSin;
  149. float Temp0b = Matrix[0][a] * -fSin + Matrix[0][b] * fCos;
  150. float Temp1b = Matrix[1][a] * -fSin + Matrix[1][b] * fCos;
  151. float Temp2b = Matrix[2][a] * -fSin + Matrix[2][b] * fCos;
  152. float Temp3b = Matrix[3][a] * -fSin + Matrix[3][b] * fCos;
  153. Matrix[0][a] = Temp0a;
  154. Matrix[1][a] = Temp1a;
  155. Matrix[2][a] = Temp2a;
  156. Matrix[3][a] = Temp3a;
  157. Matrix[0][b] = Temp0b;
  158. Matrix[1][b] = Temp1b;
  159. Matrix[2][b] = Temp2b;
  160. Matrix[3][b] = Temp3b;
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose:
  164. // Input : pt1 -
  165. // pt2 -
  166. // x1 -
  167. // y1 -
  168. // x2 -
  169. // y2 -
  170. //-----------------------------------------------------------------------------
  171. bool IsLineInside(const Vector2D &pt1, const Vector2D &pt2, int x1, int y1, int x2, int y2)
  172. {
  173. int lx1 = pt1.x;
  174. int ly1 = pt1.y;
  175. int lx2 = pt2.x;
  176. int ly2 = pt2.y;
  177. int i;
  178. // is the line totally on one side of the box?
  179. if( (lx2 > x2 && lx1 > x2) ||
  180. (lx2 < x1 && lx1 < x1) ||
  181. (ly2 > y2 && ly1 > y2) ||
  182. (ly2 < y1 && ly1 < y1) )
  183. return false;
  184. if( lx1 >= x1 && lx1 <= x2 && ly1 >= y1 && ly1 <= y2 )
  185. return true; // the first point is inside the box
  186. if( lx2 >= x1 && lx2 <= x2 && ly2 >= y1 && ly2 <= y2 )
  187. return true; // the second point is inside the box
  188. if( (ly1 > y1) != (ly2 > y1) )
  189. {
  190. i = lx1 + (int) ( (long) (y1 - ly1) * (long) (lx2 - lx1) / (long) (ly2 - ly1));
  191. if( i >= x1 && i <= x2 )
  192. return true; // the line crosses the y1 side (left)
  193. }
  194. if( (ly1 > y2) != (ly2 > y2))
  195. {
  196. i = lx1 + (int) ( (long) (y2 - ly1) * (long) (lx2 - lx1) / (long) (ly2 - ly1));
  197. if( i >= x1 && i <= x2 )
  198. return true; // the line crosses the y2 side (right)
  199. }
  200. if( (lx1 > x1) != (lx2 > x1))
  201. {
  202. i = ly1 + (int) ( (long) (x1 - lx1) * (long) (ly2 - ly1) / (long) (lx2 - lx1));
  203. if( i >= y1 && i <= y2 )
  204. return true; // the line crosses the x1 side (down)
  205. }
  206. if( (lx1 > x2) != (lx2 > x2))
  207. {
  208. i = ly1 + (int) ( (long) (x2 - lx1) * (long) (ly2 - ly1) / (long) (lx2 - lx1));
  209. if( i >= y1 && i <= y2 )
  210. return true; // the line crosses the x2 side (up)
  211. }
  212. // The line does not intersect the box.
  213. return false;
  214. }
  215. bool IsPointInside(const Vector2D &pt, const Vector2D &mins, const Vector2D &maxs )
  216. {
  217. return ( pt.x >= mins.x ) && ( pt.y >= mins.y ) && ( pt.x <= maxs.x ) && ( pt.y <= maxs.y );
  218. }
  219. // Is box 1 inside box 2?
  220. bool IsBoxInside( const Vector2D &min1, const Vector2D &max1, const Vector2D &min2, const Vector2D &max2 )
  221. {
  222. if ( ( min1.x < min2.x ) || ( max1.x > max2.x ) )
  223. return false;
  224. if ( ( min1.y < min2.y ) || ( max1.y > max2.y ) )
  225. return false;
  226. return true;
  227. }
  228. bool IsBoxIntersecting( const Vector2D &min1, const Vector2D &max1, const Vector2D &min2, const Vector2D &max2 )
  229. {
  230. if ( ( min1.x >= max2.x ) || ( max1.x <= min2.x ) )
  231. return false;
  232. if ( ( min1.y >= max2.y ) || ( max1.y <= min2.y ) )
  233. return false;
  234. return true;
  235. }
  236. void NormalizeBox( Vector &mins, Vector &maxs )
  237. {
  238. for (int i=0; i<3; i++ )
  239. {
  240. if ( mins[i] > maxs[i])
  241. {
  242. V_swap( mins[i], maxs[i] );
  243. }
  244. }
  245. }
  246. void NormalizeBox( Vector2D &mins, Vector2D &maxs )
  247. {
  248. if ( mins.x > maxs.x )
  249. {
  250. V_swap( mins.x, maxs.x );
  251. }
  252. if ( mins.y > maxs.y )
  253. {
  254. V_swap( mins.y, maxs.y );
  255. }
  256. }
  257. bool IsValidBox( Vector &mins, Vector &maxs )
  258. {
  259. return ( mins.x <= maxs.x ) && ( mins.y <= maxs.y ) && ( mins.z <= maxs.z );
  260. }
  261. bool IsValidBox( const Vector2D &mins, const Vector2D &maxs )
  262. {
  263. return ( mins.x <= maxs.x ) && ( mins.y <= maxs.y );
  264. }
  265. void LimitBox( Vector &mins, Vector &maxs, float limit )
  266. {
  267. for ( int i=0; i<3;i++)
  268. {
  269. if ( mins[i] < -limit )
  270. mins[i] = -limit;
  271. if ( maxs[i] > limit )
  272. maxs[i] = limit;
  273. }
  274. }
  275. void GetAxisFromFace( int nFace, Vector& vHorz, Vector &vVert, Vector &vThrd )
  276. {
  277. Assert( nFace >= 0 && nFace < 6);
  278. Vector points[8];
  279. PointsFromBox( Vector(0,0,0), Vector(1,1,1), points );
  280. Vector p1 = points[s_BoxFaces[nFace][0]];
  281. Vector p2 = points[s_BoxFaces[nFace][1]];
  282. Vector p3 = points[s_BoxFaces[nFace][2]];
  283. // compose equation
  284. vHorz = p2 - p1;
  285. vVert = p3 - p1;
  286. vThrd = CrossProduct( vHorz, vVert );
  287. }
  288. float IntersectionLineAABBox( const Vector& mins, const Vector& maxs, const Vector& vStart, const Vector& vEnd, int &nFace )
  289. {
  290. Vector vz = vEnd - vStart;
  291. // quick distance check first
  292. Vector vCenter = (mins+maxs)/2;
  293. Vector vTmp = maxs-vCenter;
  294. float radius = DotProduct(vTmp,vTmp);
  295. vTmp = CrossProduct(vz,(vStart-vCenter));
  296. float dist = DotProduct( vTmp,vTmp ) / DotProduct( vz,vz );
  297. nFace = -1;
  298. if ( dist > radius )
  299. {
  300. return -1;
  301. }
  302. // ok, now check against all 6 faces
  303. Vector points[8];
  304. PointsFromBox( mins, maxs, points );
  305. vz = -vz;
  306. float fDistance = 999999;
  307. for ( int i=0; i<6; i++ )
  308. {
  309. // get points of face
  310. Vector p1 = points[s_BoxFaces[i][0]];
  311. Vector p2 = points[s_BoxFaces[i][1]];
  312. Vector p3 = points[s_BoxFaces[i][2]];
  313. // compose equation
  314. Vector v0 = vStart - p1;
  315. Vector vx = p2 - p1;
  316. Vector vy = p3 - p1;
  317. Vector vOut;
  318. // solve equation v0 = x*v1 + y*v2 + z*v3
  319. if ( !SolveLinearEquation( v0, vx, vy, vz, vOut) )
  320. continue;
  321. if ( vOut.z < 0 || vOut.z > 1 )
  322. continue;
  323. if ( vOut.x < 0 || vOut.x > 1 )
  324. continue;
  325. if ( vOut.y < 0 || vOut.y > 1 )
  326. continue;
  327. if ( vOut.z < fDistance )
  328. {
  329. nFace = i;
  330. fDistance = vOut.z;
  331. }
  332. }
  333. if ( nFace >= 0 )
  334. {
  335. return fDistance*VectorLength(vz);
  336. }
  337. else
  338. {
  339. return -1;
  340. }
  341. }
  342. void RoundVector( Vector2D &v )
  343. {
  344. v.x = (int)(v.x+0.5f);
  345. v.y = (int)(v.y+0.5f);
  346. }
  347. void PointsRevertOrder( Vector *pPoints, int nPoints)
  348. {
  349. Vector *tmpPoints = (Vector*)_alloca( sizeof(Vector)*nPoints );
  350. memcpy( tmpPoints, pPoints, sizeof(Vector)*nPoints );
  351. for ( int i = 0; i<nPoints; i++)
  352. {
  353. pPoints[i] = tmpPoints[nPoints-i-1];
  354. }
  355. }
  356. const Vector &GetNormalFromFace( int nFace )
  357. {
  358. // ok, now check against all 6 faces
  359. Vector points[8];
  360. Assert( nFace>=0 && nFace<6 );
  361. PointsFromBox( Vector(0,0,0), Vector(1,1,1), points );
  362. return GetNormalFromPoints( points[s_BoxFaces[nFace][0]], points[s_BoxFaces[nFace][1]],points[s_BoxFaces[nFace][2]] );
  363. }
  364. const Vector &GetNormalFromPoints( const Vector &p0, const Vector &p1, const Vector &p2 )
  365. {
  366. static Vector vNormal;
  367. Vector v1 = p0 - p1;
  368. Vector v2 = p2 - p1;
  369. CrossProduct(v1, v2, vNormal);
  370. VectorNormalize(vNormal);
  371. return vNormal;
  372. }
  373. // solve equation v0 = x*v1 + y*v2 + z*v3
  374. bool SolveLinearEquation( const Vector& v0, const Vector& v1, const Vector& v2, const Vector& v3, Vector& vOut)
  375. {
  376. VMatrix matrix, inverse;
  377. matrix.Init(
  378. v1.x, v1.y, v1.z, 0,
  379. v2.x, v2.y, v2.z, 0,
  380. v3.x, v3.y, v3.z, 0,
  381. 0.0f, 0.0f, 0.0f, 1
  382. );
  383. if( !matrix.InverseGeneral(inverse) )
  384. return false;
  385. vOut = inverse.VMul3x3Transpose( v0 );
  386. return true;
  387. }
  388. bool BuildAxesFromNormal( const Vector &vNormal, Vector &vHorz, Vector &vVert )
  389. {
  390. vHorz.Init();
  391. vVert.Init();
  392. // find the major axis
  393. float bestMin = 99999;
  394. int bestAxis = -1;
  395. for (int i=0 ; i<3; i++)
  396. {
  397. float a = fabs(vNormal[i]);
  398. if (a < bestMin)
  399. {
  400. bestAxis = i;
  401. bestMin = a;
  402. }
  403. }
  404. if (bestAxis==-1)
  405. return false;
  406. vHorz[bestAxis] = 1;
  407. CrossProduct( vNormal,vHorz,vVert);
  408. CrossProduct( vNormal,vVert,vHorz);
  409. VectorNormalize( vHorz );
  410. VectorNormalize( vVert );
  411. return true;
  412. }