EMath.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /***************************************************************************
  2. EMath.cpp - description
  3. -------------------
  4. begin : Sat Jan 29 2000
  5. copyright : (C) 2000 by
  6. email :
  7. ***************************************************************************/
  8. #include <math.h>
  9. #include <stdlib.h>
  10. #include "Private.h"
  11. #include "EMath.h"
  12. #if EM_USE_FAST_FLOAT2INT
  13. IntOrFloat gBias; //.i = (23 + 127) << 23;
  14. #endif
  15. const Matrix EMath::identityMatrix =
  16. {
  17. {
  18. /* 3x3 identity */
  19. { 1.0f, 0.0f, 0.0f },
  20. { 0.0f, 1.0f, 0.0f },
  21. { 0.0f, 0.0f, 1.0f },
  22. },
  23. /* zero translation */
  24. { 0.0f, 0.0f, 0.0f }
  25. };
  26. EMath::EMath() {
  27. }
  28. EMath::~EMath() {
  29. }
  30. // void EMath::applyMatrix(const Matrix & mtx, const Vertex3D & vtxIn, Vertex3D & vtxOut) {
  31. // vtxOut.x = vtxIn.x * mtx.v[0][0] + vtxIn.y * mtx.v[0][1] + vtxIn.z * mtx.v[0][2] + mtx.t[0];
  32. // vtxOut.y = vtxIn.x * mtx.v[1][0] + vtxIn.y * mtx.v[1][1] + vtxIn.z * mtx.v[1][2] + mtx.t[1];
  33. // vtxOut.z = vtxIn.x * mtx.v[2][0] + vtxIn.y * mtx.v[2][1] + vtxIn.z * mtx.v[2][2] + mtx.t[2];
  34. // }
  35. void EMath::applyMatrixTrans(const Matrix & mtx, const Vertex3D & vtxIn, Vertex3D & vtxOut) {
  36. vtxOut.x = vtxIn.x + mtx.t[0];
  37. vtxOut.y = vtxIn.y + mtx.t[1];
  38. vtxOut.z = vtxIn.z + mtx.t[2];
  39. }
  40. void EMath::crossProduct(const Vertex3D & vtxA, const Vertex3D & vtxB, Vertex3D & vtxOut) {
  41. vtxOut.x = (vtxA.y * vtxB.z) - (vtxA.z * vtxB.y);
  42. vtxOut.y = (vtxA.z * vtxB.x) - (vtxA.x * vtxB.z);
  43. vtxOut.z = (vtxA.x * vtxB.y) - (vtxA.y * vtxB.x);
  44. }
  45. float EMath::dotProduct(const Vertex3D & vtxA, const Vertex3D & vtxB) {
  46. return vtxA.x * vtxB.x + vtxA.y * vtxB.y + vtxA.z * vtxB.z;
  47. }
  48. float EMath::emAcos(float f) {
  49. return (float) acos(EM_PI_2*f);
  50. }
  51. float EMath::emAtan(float f) {
  52. return (float)atan(EM_PI_2*f);
  53. }
  54. float EMath::emCos(float f) {
  55. return (float)cos(EM_PI_2*f);
  56. }
  57. float EMath::emRand() {
  58. return ((float)(rand()-(RAND_MAX/2))/(RAND_MAX/2));
  59. }
  60. float EMath::emSin(float f) {
  61. return (float)sin(EM_PI_2*f);
  62. }
  63. float EMath::emSqrt(float f) {
  64. return (float)sqrt(f);
  65. }
  66. float EMath::emTan(float f) {
  67. return (float)tan(EM_PI_2*f);
  68. }
  69. float EMath::emPow(float x, float y) {
  70. return (float)pow(x, y);
  71. }
  72. /* */
  73. void EMath::getTransformationMatrix(Matrix & mtx, const Vertex3D & vtxT,
  74. const Vertex3D & vtxR, const Vertex3D & vtxS) {
  75. float sin_x = EMath::emSin(vtxR.x);
  76. float cos_x = EMath::emCos(vtxR.x);
  77. float sin_y = EMath::emSin(vtxR.y);
  78. float cos_y = EMath::emCos(vtxR.y);
  79. float sin_z = EMath::emSin(vtxR.z);
  80. float cos_z = EMath::emCos(vtxR.z);
  81. float sinx_siny = sin_x * sin_y;
  82. float cosx_siny = cos_x * sin_y;
  83. mtx.v[0][0] = cos_y * cos_z * vtxS.x;
  84. mtx.v[0][1] = cos_y * sin_z;
  85. mtx.v[0][2] = -sin_y;
  86. mtx.v[1][0] = (sinx_siny * cos_z) - (cos_x * sin_z);
  87. mtx.v[1][1] = (sinx_siny * sin_z) + (cos_x * cos_z) * vtxS.y;
  88. mtx.v[1][2] = sin_x * cos_y;
  89. mtx.v[2][0] = (cosx_siny * cos_z) + (sin_x * sin_z);
  90. mtx.v[2][1] = (cosx_siny * sin_z) - (sin_x * cos_z);
  91. mtx.v[2][2] = cos_x * cos_y * vtxS.z;
  92. mtx.t[0] = vtxT.x;
  93. mtx.t[1] = vtxT.y;
  94. mtx.t[2] = vtxT.z;
  95. }
  96. void EMath::getTransformationMatrix(Matrix & mtx, const Vertex3D & vtxT,
  97. const Quaternion & qRot, const Vertex3D & vtxS) {
  98. // a lean function for filling m[16] with
  99. // a 4x4 transformation matrix based on
  100. // translation v and rotation q
  101. // This routine would likely be used by an opengl
  102. // programmer calling glmultmatrix()
  103. mtx.v[0][0] = 1 - 2*(qRot.y*qRot.y + qRot.z*qRot.z) * vtxS.x;
  104. mtx.v[0][1] = 2*(qRot.x*qRot.y + qRot.w*qRot.z);
  105. mtx.v[0][2] = 2*(qRot.x*qRot.z - qRot.w*qRot.y);
  106. mtx.v[1][0] = 2*(qRot.x*qRot.y - qRot.w*qRot.z);
  107. mtx.v[1][1] = 1 - 2*(qRot.x*qRot.x + qRot.z*qRot.z) * vtxS.y;
  108. mtx.v[1][2] = 2*(qRot.y*qRot.z + qRot.w*qRot.x);
  109. mtx.v[2][0] = 2*(qRot.x*qRot.z + qRot.w*qRot.y);
  110. mtx.v[2][1] = 2*(qRot.y*qRot.z - qRot.w*qRot.x);
  111. mtx.v[2][2] = 1-2*(qRot.x*qRot.x + qRot.y*qRot.y) * vtxS.z;
  112. /*
  113. mtx.v[0][0] = 1 - 2*(qRot.y*qRot.y + qRot.z*qRot.z);
  114. mtx.v[1][0] = 2*(qRot.x*qRot.y + qRot.w*qRot.z);
  115. mtx.v[2][0] = 2*(qRot.x*qRot.z - qRot.w*qRot.y);
  116. mtx.v[0][1] = 2*(qRot.x*qRot.y - qRot.w*qRot.z);
  117. mtx.v[1][1] = 1 - 2*(qRot.x*qRot.x + qRot.z*qRot.z);
  118. mtx.v[2][1] = 2*(qRot.y*qRot.z + qRot.w*qRot.x);
  119. mtx.v[0][2] = 2*(qRot.x*qRot.z + qRot.w*qRot.y);
  120. mtx.v[1][2] = 2*(qRot.y*qRot.z - qRot.w*qRot.x);
  121. mtx.v[2][2] = 1-2*(qRot.x*qRot.x + qRot.y*qRot.y);
  122. */
  123. mtx.t[0] = vtxT.x;
  124. mtx.t[1] = vtxT.y;
  125. mtx.t[2] = vtxT.z;
  126. }
  127. /* Stolen from allegro. Thanks!! */
  128. void EMath::inverse(const Matrix & mtx, Matrix & inv) {
  129. Matrix mtxTmp = mtx;
  130. inv = identityMatrix;
  131. int cc;
  132. int rowMax; // Points to max abs value row in this column
  133. int row;
  134. float tmp;
  135. // Go through columns
  136. for (int c=0; c<3; c++) {
  137. // Find the row with max value in this column
  138. rowMax = c;
  139. for (int r=c+1; r<3; r++) {
  140. if (fabs(mtxTmp.v[c][r]) > fabs(mtxTmp.v[c][rowMax])) {
  141. rowMax = r;
  142. }
  143. }
  144. // If the max value here is 0, we can't invert. Return identity.
  145. if (mtx.v[rowMax][c] == 0.0f) {
  146. inv = identityMatrix;
  147. return;
  148. }
  149. // Swap row "rowMax" with row "c"
  150. for (cc=0; cc<3; cc++) {
  151. tmp = mtxTmp.v[cc][c];
  152. mtxTmp.v[cc][c] = mtxTmp.v[cc][rowMax];
  153. mtxTmp.v[cc][rowMax] = tmp;
  154. tmp = inv.v[cc][c];
  155. inv.v[cc][c] = inv.v[cc][rowMax];
  156. inv.v[cc][rowMax] = tmp;
  157. }
  158. // Now everything we do is on row "c".
  159. // Set the max cell to 1 by dividing the entire row by that value
  160. tmp = mtxTmp.v[c][c];
  161. for (cc=0; cc<3; cc++) {
  162. mtxTmp.v[cc][c] /= tmp;
  163. inv.v[cc][c] /= tmp;
  164. }
  165. // Now do the other rows, so that this column only has a 1 and 0's
  166. for (row = 0; row < 3; row++) {
  167. if (row != c) {
  168. tmp = mtxTmp.v[c][row];
  169. for (cc=0; cc<3; cc++) {
  170. mtxTmp.v[cc][row] -= mtxTmp.v[cc][c] * tmp;
  171. inv.v[cc][row] -= inv.v[cc][c] * tmp;
  172. }
  173. }
  174. }
  175. }
  176. inv.t[0] = -mtx.t[0];
  177. inv.t[1] = -mtx.t[1];
  178. inv.t[2] = -mtx.t[2];
  179. }
  180. /* mtxA or mtxB NOT allowed to be the same as out.
  181. */
  182. void EMath::matrixMulti(const Matrix & mtxA, const Matrix & mtxB, Matrix & mtxOut) {
  183. for (int a=0; a<3; a++) {
  184. for (int b=0; b<3; b++) {
  185. mtxOut.v[a][b] =
  186. (mtxA.v[0][b] * mtxB.v[a][0]) +
  187. (mtxA.v[1][b] * mtxB.v[a][1]) +
  188. (mtxA.v[2][b] * mtxB.v[a][2]);
  189. }
  190. mtxOut.t[a] =
  191. (mtxA.t[0] * mtxB.v[a][0]) +
  192. (mtxA.t[1] * mtxB.v[a][1]) +
  193. (mtxA.t[2] * mtxB.v[a][2]) +
  194. mtxB.t[a];
  195. }
  196. }
  197. void EMath::planeLineIntersection(const Vertex3D & nrml, float dist,
  198. const Vertex3D & vtxA, const Vertex3D & vtxB, Vertex3D & vtxDiff) {
  199. // returns the point where the line p1-p2 intersects the plane n&d
  200. EMath::subst(vtxB, vtxA, vtxDiff);
  201. float dot = EMath::dotProduct(nrml, vtxDiff);
  202. float k = -(dist + EMath::dotProduct(nrml, vtxA) ) / dot;
  203. EMath::scaleVertex(vtxDiff, k);
  204. EMath::add(vtxA, vtxDiff);
  205. }
  206. /* */
  207. void EMath::normalizeVector(Vertex3D & vtx) {
  208. float length_1;
  209. float length = EMath::vectorLength(vtx);
  210. if (EM_ZERO(length)) {
  211. vtx.x = 0.0f;
  212. vtx.y = 1.0f;
  213. vtx.z = 0.0f;
  214. return;
  215. }
  216. length_1 = 1.0f / length;
  217. vtx.x *= length_1;
  218. vtx.y *= length_1;
  219. vtx.z *= length_1;
  220. }
  221. /* */
  222. void EMath::scaleVector(Vertex3D & vtx, float sc) {
  223. vtx.x *= sc;
  224. vtx.y *= sc;
  225. vtx.z *= sc;
  226. }
  227. /* Projection of vector A onto B. */
  228. float EMath::projection(const Vertex3D & vtxA, const Vertex3D & vtxB, Vertex3D & vtxOut) {
  229. float k =(vtxA.x * vtxB.x + vtxA.y * vtxB.y + vtxA.z * vtxB.z) /
  230. (vtxB.x * vtxB.x + vtxB.y * vtxB.y + vtxB.z * vtxB.z);
  231. vtxOut.x = k * vtxB.x;
  232. vtxOut.y = k * vtxB.y;
  233. vtxOut.z = k * vtxB.z;
  234. return k;
  235. }
  236. float EMath::perpendicular(const Vertex3D & vtxA, const Vertex3D & vtxB, Vertex3D & vtxOut) {
  237. float k =(vtxA.x * vtxB.x + vtxA.y * vtxB.y + vtxA.z * vtxB.z) /
  238. (vtxB.x * vtxB.x + vtxB.y * vtxB.y + vtxB.z * vtxB.z);
  239. vtxOut.x = vtxA.x - k * vtxB.x;
  240. vtxOut.y = vtxA.y - k * vtxB.y;
  241. vtxOut.z = vtxA.z - k * vtxB.z;
  242. return k;
  243. }
  244. /* */
  245. float EMath::polygonZNormal(const Vertex3D & edgeA, const Vertex3D & edgeB,
  246. const Vertex3D & edgeC) {
  247. return ((edgeB.x - edgeA.x) * (edgeC.y - edgeB.y)) - ((edgeC.x - edgeB.x) * (edgeB.y - edgeA.y));
  248. }
  249. /* First the projection of vtxIn onto vtxWall is counted.
  250. * the reflection is then vtxOut = vtxIn - 2*vtxPro.
  251. * If k > 0 the vtxIn vector is comming from behind the wall and
  252. * no reflection is made. */
  253. void EMath::reflection(const Vertex3D & vtxIn, const Vertex3D & vtxWall, Vertex3D & vtxOut,
  254. bool bBehind) {
  255. Vertex3D vtxPro;
  256. float k =(vtxIn.x * vtxWall.x + vtxIn.y * vtxWall.y + vtxIn.z * vtxWall.z) /
  257. (vtxWall.x * vtxWall.x + vtxWall.y * vtxWall.y + vtxWall.z * vtxWall.z);
  258. if ( k < 0 || bBehind) {
  259. vtxPro.x = k * vtxWall.x;
  260. vtxPro.y = k * vtxWall.y;
  261. vtxPro.z = k * vtxWall.z;
  262. vtxOut.x = - vtxPro.x - vtxPro.x + vtxIn.x;
  263. vtxOut.y = - vtxPro.y - vtxPro.y + vtxIn.y;
  264. vtxOut.z = - vtxPro.z - vtxPro.z + vtxIn.z;
  265. }
  266. }
  267. /* First the projection of vtxIn onto vtxWall is counted.
  268. * the reflection is then vtxOut = vtxIn - 2*vtxPro.
  269. * If k > 0 the vtxIn vector is comming from behind the wall and
  270. * no reflection is made. */
  271. void EMath::reflectionDamp(const Vertex3D & vtxIn, const Vertex3D & vtxWall, Vertex3D & vtxOut,
  272. float damp, float extra, float scale, bool bBehind) {
  273. Vertex3D vtxPro;
  274. float k =(vtxIn.x * vtxWall.x + vtxIn.y * vtxWall.y + vtxIn.z * vtxWall.z) /
  275. (vtxWall.x * vtxWall.x + vtxWall.y * vtxWall.y + vtxWall.z * vtxWall.z);
  276. if ( k < 0 || bBehind) {
  277. vtxPro.x = k * vtxWall.x;
  278. vtxPro.y = k * vtxWall.y;
  279. vtxPro.z = k * vtxWall.z;
  280. vtxOut.x = (vtxIn.x - vtxPro.x - vtxPro.x * damp + vtxWall.x * extra) * scale;
  281. vtxOut.y = (vtxIn.y - vtxPro.y - vtxPro.y * damp + vtxWall.y * extra) * scale;
  282. vtxOut.z = (vtxIn.z - vtxPro.z - vtxPro.z * damp + vtxWall.z * extra) * scale;
  283. }
  284. }
  285. /*
  286. float EMath::vectorLength(const Vertex3D & vtx) {
  287. return EMath::emSqrt(vtx.x * vtx.x + vtx.y * vtx.y + vtx.z * vtx.z);
  288. }
  289. float EMath::vectorLengthSqr(const Vertex3D & vtx) {
  290. return (vtx.x * vtx.x + vtx.y * vtx.y + vtx.z * vtx.z);
  291. }
  292. */
  293. /* */
  294. float EMath::volume(const Vertex3D & vtxA, const Vertex3D & vtxB, const Vertex3D & vtxC) {
  295. return vtxA.x*( vtxB.y*vtxC.z - vtxB.z*vtxC.y ) -
  296. vtxA.y*( vtxB.x*vtxC.z - vtxB.z*vtxC.x ) +
  297. vtxA.z*( vtxB.x*vtxC.y - vtxB.y*vtxC.x );
  298. }
  299. void EMath::rotationArc(const Vertex3D & vtxa, const Vertex3D & vtxb, Quaternion & qOut) {
  300. Vertex3D vtxA = vtxa;
  301. Vertex3D vtxB = vtxb;
  302. EMath::normalizeVector(vtxA);
  303. EMath::normalizeVector(vtxB);
  304. Vertex3D vtxCross;
  305. EMath::crossProduct(vtxA, vtxB, vtxCross);
  306. float dot = EMath::dotProduct(vtxA, vtxB);
  307. float sq = EMath::emSqrt((1+dot)*2);
  308. qOut.x = vtxCross.x / sq;
  309. qOut.y = vtxCross.y / sq;
  310. qOut.z = vtxCross.z / sq;
  311. qOut.w = sq / 2.0f;
  312. }
  313. void EMath::quaternionMulti(const Quaternion & qA, const Quaternion & qB, Quaternion & qOut) {
  314. qOut.w = qA.w*qB.w - qA.x*qB.x - qA.y*qB.y - qA.z*qB.z;
  315. qOut.x = qA.w*qB.x + qA.x*qB.w + qA.y*qB.z - qA.z*qB.y;
  316. qOut.y = qA.w*qB.y - qA.x*qB.z + qA.y*qB.w + qA.z*qB.x;
  317. qOut.z = qA.w*qB.z + qA.x*qB.y - qA.y*qB.x + qA.z*qB.w;
  318. }
  319. float EMath::quadratic(float f0, float f1, float f2, float t) {
  320. // this was a beizer curve
  321. // float t1 = 1.0f - t;
  322. // return t1*t1*f0 + 2.0f*t*t1*f1 + t*t*f2;
  323. float df1 = f1 - f0;
  324. float df2 = f2 - f1;
  325. float ddf = df2 - df1;
  326. return f0 + t*df1 + 0.5f*t*(t-1.0f)*ddf;
  327. }
  328. float EMath::cubic(float f0, float f1, float f2, float f3, float t) {
  329. float df1 = f1 - f0;
  330. float df2 = f2 - f1;
  331. float df3 = f3 - f2;
  332. float ddf1 = df2 - df1;
  333. float ddf2 = df3 - df2;
  334. float dddf = ddf2 - ddf1;
  335. return f0 + t*df1 + 0.5*t*(t-1.0f)*ddf1 + 0.166667f*t*(t-1.0f)*(t-2.0f)*dddf;
  336. }