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.

559 lines
12 KiB

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