Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Matrix.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*!
  2. * \file src/Matrix.cpp
  3. * \brief 3D Matrix
  4. *
  5. * \author Mongoose
  6. */
  7. #include <stdio.h>
  8. #include <math.h>
  9. #include "Matrix.h"
  10. Matrix::Matrix() {
  11. setIdentity();
  12. }
  13. Matrix::Matrix(matrix_t m) {
  14. setMatrix(m);
  15. }
  16. Matrix::Matrix(Quaternion &q) {
  17. matrix_t m;
  18. q.getMatrix(m);
  19. setMatrix(m);
  20. }
  21. Matrix::~Matrix() {
  22. }
  23. bool Matrix::getInvert(matrix_t out) {
  24. matrix_t m;
  25. #ifdef COLUMN_ORDER
  26. getMatrix(m);
  27. #else
  28. getTransposeMatrix(m);
  29. #endif
  30. /* Mongoose: This code was from a Jeff Lander tutorial which was based
  31. on MESA GL's InvertMatrix */
  32. /* NB. OpenGL Matrices are COLUMN major. */
  33. #define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; }
  34. #define MAT(m,r,c) (m)[(c)*4+(r)]
  35. float wtmp[4][8];
  36. float m0, m1, m2, m3, s;
  37. float *r0, *r1, *r2, *r3;
  38. r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
  39. r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
  40. r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
  41. r0[4] = 1.0f, r0[5] = r0[6] = r0[7] = 0.0f,
  42. r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
  43. r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
  44. r1[5] = 1.0f, r1[4] = r1[6] = r1[7] = 0.0f,
  45. r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
  46. r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
  47. r2[6] = 1.0f, r2[4] = r2[5] = r2[7] = 0.0f,
  48. r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
  49. r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
  50. r3[7] = 1.0f, r3[4] = r3[5] = r3[6] = 0.0f;
  51. /* choose pivot - or die */
  52. if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
  53. if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
  54. if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
  55. if (0.0f == r0[0]) return false;
  56. /* eliminate first variable */
  57. m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
  58. s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
  59. s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
  60. s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
  61. s = r0[4];
  62. if (s != 0.0f) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
  63. s = r0[5];
  64. if (s != 0.0f) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
  65. s = r0[6];
  66. if (s != 0.0f) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
  67. s = r0[7];
  68. if (s != 0.0f) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
  69. /* choose pivot - or die */
  70. if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
  71. if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
  72. if (0.0f == r1[1]) return false;
  73. /* eliminate second variable */
  74. m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
  75. r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
  76. r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
  77. s = r1[4]; if (0.0f != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
  78. s = r1[5]; if (0.0f != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
  79. s = r1[6]; if (0.0f != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
  80. s = r1[7]; if (0.0f != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
  81. /* choose pivot - or die */
  82. if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
  83. if (0.0f == r2[2]) return false;
  84. /* eliminate third variable */
  85. m3 = r3[2]/r2[2];
  86. r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
  87. r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
  88. r3[7] -= m3 * r2[7];
  89. /* last check */
  90. if (0.0f == r3[3]) return false;
  91. s = 1.0f/r3[3]; /* now back substitute row 3 */
  92. r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
  93. m2 = r2[3]; /* now back substitute row 2 */
  94. s = 1.0f/r2[2];
  95. r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
  96. r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
  97. m1 = r1[3];
  98. r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
  99. r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
  100. m0 = r0[3];
  101. r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
  102. r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
  103. m1 = r1[2]; /* now back substitute row 1 */
  104. s = 1.0f/r1[1];
  105. r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
  106. r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
  107. m0 = r0[2];
  108. r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
  109. r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
  110. m0 = r0[1]; /* now back substitute row 0 */
  111. s = 1.0f/r0[0];
  112. r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
  113. r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
  114. MAT(out,0,0) = r0[4];
  115. MAT(out,0,1) = r0[5], MAT(out,0,2) = r0[6];
  116. MAT(out,0,3) = r0[7], MAT(out,1,0) = r1[4];
  117. MAT(out,1,1) = r1[5], MAT(out,1,2) = r1[6];
  118. MAT(out,1,3) = r1[7], MAT(out,2,0) = r2[4];
  119. MAT(out,2,1) = r2[5], MAT(out,2,2) = r2[6];
  120. MAT(out,2,3) = r2[7], MAT(out,3,0) = r3[4];
  121. MAT(out,3,1) = r3[5], MAT(out,3,2) = r3[6];
  122. MAT(out,3,3) = r3[7];
  123. return true;
  124. #undef MAT
  125. #undef SWAP_ROWS
  126. }
  127. void Matrix::getMatrix(matrix_t mat) {
  128. copy(mMatrix, mat);
  129. }
  130. void Matrix::getTransposeMatrix(matrix_t m) {
  131. m[ 0]= mMatrix[0]; m[ 1]= mMatrix[4]; m[ 2]= mMatrix[ 8]; m[ 3]=mMatrix[12];
  132. m[ 4]= mMatrix[1]; m[ 5]= mMatrix[5]; m[ 6]= mMatrix[ 9]; m[ 7]=mMatrix[13];
  133. m[ 8]= mMatrix[2]; m[ 9]= mMatrix[6]; m[10]= mMatrix[10]; m[11]=mMatrix[14];
  134. m[12]= mMatrix[3]; m[13]= mMatrix[7]; m[14]= mMatrix[11]; m[15]=mMatrix[15];
  135. }
  136. Matrix Matrix::multiply(const Matrix &a, const Matrix &b) {
  137. Matrix c;
  138. multiply(a.mMatrix, b.mMatrix, c.mMatrix);
  139. return c;
  140. }
  141. Matrix Matrix::operator *(const Matrix &a) {
  142. return multiply(a, *this);
  143. }
  144. Vector3d Matrix::operator *(Vector3d v) {
  145. vec_t x = v.mVec[0], y = v.mVec[1], z = v.mVec[2];
  146. #ifdef COLUMN_ORDER
  147. return Vector3d(mMatrix[0]*x + mMatrix[4]*y + mMatrix[ 8]*z + mMatrix[12],
  148. mMatrix[1]*x + mMatrix[5]*y + mMatrix[ 9]*z + mMatrix[13],
  149. mMatrix[2]*x + mMatrix[6]*y + mMatrix[10]*z + mMatrix[14]);
  150. #else
  151. return Vector3d(mMatrix[0]*x + mMatrix[1]*y + mMatrix[ 2]*z + mMatrix[ 3],
  152. mMatrix[4]*x + mMatrix[5]*y + mMatrix[ 6]*z + mMatrix[ 7],
  153. mMatrix[8]*x + mMatrix[9]*y + mMatrix[10]*z + mMatrix[11]);
  154. #endif
  155. }
  156. void Matrix::multiply3v(vec3_t v, vec3_t result) {
  157. vec_t x = v[0], y = v[1], z = v[2];
  158. result[0] = mMatrix[0]*x + mMatrix[1]*y + mMatrix[ 2]*z + mMatrix[ 3];
  159. result[1] = mMatrix[4]*x + mMatrix[5]*y + mMatrix[ 6]*z + mMatrix[ 7];
  160. result[2] = mMatrix[8]*x + mMatrix[9]*y + mMatrix[10]*z + mMatrix[11];
  161. }
  162. void Matrix::multiply4v(vec4_t v, vec4_t result) {
  163. vec_t x = v[0], y = v[1], z = v[2], w = v[3];
  164. result[0] = mMatrix[ 0]*x + mMatrix[ 1]*y + mMatrix[ 2]*z + mMatrix[ 3]*w;
  165. result[1] = mMatrix[ 4]*x + mMatrix[ 5]*y + mMatrix[ 6]*z + mMatrix[ 7]*w;
  166. result[2] = mMatrix[ 8]*x + mMatrix[ 9]*y + mMatrix[10]*z + mMatrix[11]*w;
  167. result[3] = mMatrix[12]*x + mMatrix[13]*y + mMatrix[14]*z + mMatrix[15]*w;
  168. }
  169. void Matrix::print() {
  170. printf("{\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n}\n",
  171. #ifdef COLUMN_ORDER
  172. mMatrix[0], mMatrix[4], mMatrix[ 8], mMatrix[12],
  173. mMatrix[1], mMatrix[5], mMatrix[ 9], mMatrix[13],
  174. mMatrix[2], mMatrix[6], mMatrix[10], mMatrix[14],
  175. mMatrix[3], mMatrix[7], mMatrix[11], mMatrix[15]);
  176. #else
  177. mMatrix[ 0], mMatrix[ 1], mMatrix[ 2], mMatrix[ 3],
  178. mMatrix[ 4], mMatrix[ 5], mMatrix[ 6], mMatrix[ 7],
  179. mMatrix[ 8], mMatrix[ 9], mMatrix[10], mMatrix[11],
  180. mMatrix[12], mMatrix[13], mMatrix[14], mMatrix[15]);
  181. #endif
  182. }
  183. bool Matrix::isIdentity() {
  184. // Hhhmm... floating point using direct comparisons
  185. /*
  186. if (mMatrix[ 0] == 1 && mMatrix[ 1] == 0 && mMatrix[ 2] == 0 &&
  187. mMatrix[ 3] == 0 && mMatrix[ 4] == 0 && mMatrix[ 5] == 1 &&
  188. mMatrix[ 6] == 0 && mMatrix[ 7] == 0 && mMatrix[ 8] == 0 &&
  189. mMatrix[ 9] == 0 && mMatrix[10] == 1 && mMatrix[11] == 0 &&
  190. mMatrix[12] == 0 && mMatrix[13] == 0 && mMatrix[14] == 0 &&
  191. mMatrix[15] == 1)
  192. return true;
  193. */
  194. if (equalEpsilon(mMatrix[ 0], 1.0) && equalEpsilon(mMatrix[ 1], 0.0) && equalEpsilon(mMatrix[ 2], 0.0) &&
  195. equalEpsilon(mMatrix[ 3], 0.0) && equalEpsilon(mMatrix[ 4], 0.0) && equalEpsilon(mMatrix[ 5], 1.0) &&
  196. equalEpsilon(mMatrix[ 6], 0.0) && equalEpsilon(mMatrix[ 7], 0.0) && equalEpsilon(mMatrix[ 8], 0.0) &&
  197. equalEpsilon(mMatrix[ 9], 0.0) && equalEpsilon(mMatrix[10], 1.0) && equalEpsilon(mMatrix[11], 0.0) &&
  198. equalEpsilon(mMatrix[12], 0.0) && equalEpsilon(mMatrix[13], 0.0) && equalEpsilon(mMatrix[14], 0.0) &&
  199. equalEpsilon(mMatrix[15], 1.0))
  200. return true;
  201. return false;
  202. }
  203. void Matrix::setMatrix(matrix_t mat) {
  204. copy(mat, mMatrix);
  205. }
  206. void Matrix::setIdentity() {
  207. mMatrix[ 0] = 1; mMatrix[ 1] = 0; mMatrix[ 2] = 0; mMatrix[ 3] = 0;
  208. mMatrix[ 4] = 0; mMatrix[ 5] = 1; mMatrix[ 6] = 0; mMatrix[ 7] = 0;
  209. mMatrix[ 8] = 0; mMatrix[ 9] = 0; mMatrix[10] = 1; mMatrix[11] = 0;
  210. mMatrix[12] = 0; mMatrix[13] = 0; mMatrix[14] = 0; mMatrix[15] = 1;
  211. }
  212. void Matrix::scale(const vec_t *xyz) {
  213. scale(xyz[0], xyz[1], xyz[2]);
  214. }
  215. void Matrix::scale(vec_t sx, vec_t sy, vec_t sz) {
  216. matrix_t smatrix;
  217. matrix_t tmp;
  218. smatrix[ 0] = sx; smatrix[ 1] = 0; smatrix[ 2] = 0; smatrix[ 3] = 0;
  219. smatrix[ 4] = 0; smatrix[ 5] = sy; smatrix[ 6] = 0; smatrix[ 7] = 0;
  220. smatrix[ 8] = 0; smatrix[ 9] = 0; smatrix[10] = sz; smatrix[11] = 0;
  221. smatrix[12] = 0; smatrix[13] = 0; smatrix[14] = 0; smatrix[15] = 1;
  222. copy(mMatrix, tmp);
  223. multiply(tmp, smatrix, mMatrix);
  224. }
  225. void Matrix::rotate(const vec_t *xyz) {
  226. rotate(xyz[0], xyz[1], xyz[2]);
  227. }
  228. void Matrix::rotate(vec_t ax, vec_t ay, vec_t az) {
  229. matrix_t xmat, ymat, zmat, tmp, tmp2;
  230. xmat[ 0]=1; xmat[ 1]=0; xmat[ 2]=0; xmat[ 3]=0;
  231. xmat[ 4]=0; xmat[ 5]=cosf(ax); xmat[ 6]=sinf(ax); xmat[ 7]=0;
  232. xmat[ 8]=0; xmat[ 9]=-sinf(ax); xmat[10]=cosf(ax); xmat[11]=0;
  233. xmat[12]=0; xmat[13]=0; xmat[14]=0; xmat[15]=1;
  234. ymat[ 0]=cosf(ay); ymat[ 1]=0; ymat[ 2]=-sinf(ay); ymat[ 3]=0;
  235. ymat[ 4]=0; ymat[ 5]=1; ymat[ 6]=0; ymat[ 7]=0;
  236. ymat[ 8]=sinf(ay); ymat[ 9]=0; ymat[10]=cosf(ay); ymat[11]=0;
  237. ymat[12]=0; ymat[13]=0; ymat[14]=0; ymat[15]=1;
  238. zmat[ 0]=cosf(az); zmat[ 1]=sinf(az); zmat[ 2]=0; zmat[ 3]=0;
  239. zmat[ 4]=-sinf(az); zmat[ 5]=cosf(az); zmat[ 6]=0; zmat[ 7]=0;
  240. zmat[ 8]=0; zmat[ 9]=0; zmat[10]=1; zmat[11]=0;
  241. zmat[12]=0; zmat[13]=0; zmat[14]=0; zmat[15]=1;
  242. multiply(mMatrix, ymat, tmp);
  243. multiply(tmp, xmat, tmp2);
  244. multiply(tmp2, zmat, mMatrix);
  245. }
  246. void Matrix::translate(const vec_t *xyz) {
  247. translate(xyz[0], xyz[1], xyz[2]);
  248. }
  249. void Matrix::translate(vec_t tx, vec_t ty, vec_t tz) {
  250. matrix_t tmat, tmp;
  251. tmat[ 0]=1; tmat[ 1]=0; tmat[ 2]=0; tmat[ 3]=0;
  252. tmat[ 4]=0; tmat[ 5]=1; tmat[ 6]=0; tmat[ 7]=0;
  253. tmat[ 8]=0; tmat[ 9]=0; tmat[10]=1; tmat[11]=0;
  254. tmat[12]=tx; tmat[13]=ty; tmat[14]=tz; tmat[15]=1;
  255. copy(mMatrix, tmp);
  256. multiply(tmp, tmat, mMatrix);
  257. }
  258. void Matrix::copy(matrix_t source, matrix_t dest) {
  259. for (int i = 0; i < 16; i++)
  260. dest[i] = source[i];
  261. }
  262. void Matrix::multiply(const matrix_t a, const matrix_t b, matrix_t result) {
  263. /* Generated code for matrix mult
  264. * Code used:
  265. // char order is argument
  266. int i, j, k;
  267. if (order == 'r') {
  268. printf("// Row order\n");
  269. } else {
  270. printf("// Column order\n");
  271. }
  272. for (i = 0; i < 4; ++i) {
  273. for (j = 0; j < 4; ++j) {
  274. if (order == 'r') {
  275. printf("result[%2i] = ", j+i*4);
  276. } else {
  277. printf("result[%2i] = ", j+i*4);
  278. }
  279. for (k = 0; k < 4; ++k) {
  280. if (order == 'r') {
  281. printf("a[%2i] * b[%2i]%s",
  282. k+i*4, j+k*4, (k == 3) ? ";\n" : " + ");
  283. } else {
  284. printf("a[%2i] * b[%2i]%s",
  285. i+k*4, k+j*4, (k == 3) ? ";\n" : " + ");
  286. }
  287. //sum+=(elements[i+k*4]*m.elements[k+j*4]);
  288. }
  289. //result.elements[i+j*4]=sum;
  290. }
  291. printf("\n");
  292. }
  293. printf("\n");
  294. printf("// Transpose\n");
  295. for(i = 0; i < 4; ++i) {
  296. for (j = 0; j < 4; ++j) {
  297. printf("a[%2i] = b[%2i]%s",
  298. j+i*4, i+j*4, (j == 3) ? ";\n" : "; ");
  299. }
  300. }
  301. * was in test/Matrix.cpp
  302. */
  303. #ifdef COLUMN_ORDER
  304. /* Column order */
  305. result[ 0] = a[ 0] * b[ 0] + a[ 4] * b[ 1] + a[ 8] * b[ 2] + a[12] * b[ 3];
  306. result[ 1] = a[ 0] * b[ 4] + a[ 4] * b[ 5] + a[ 8] * b[ 6] + a[12] * b[ 7];
  307. result[ 2] = a[ 0] * b[ 8] + a[ 4] * b[ 9] + a[ 8] * b[10] + a[12] * b[11];
  308. result[ 3] = a[ 0] * b[12] + a[ 4] * b[13] + a[ 8] * b[14] + a[12] * b[15];
  309. result[ 4] = a[ 1] * b[ 0] + a[ 5] * b[ 1] + a[ 9] * b[ 2] + a[13] * b[ 3];
  310. result[ 5] = a[ 1] * b[ 4] + a[ 5] * b[ 5] + a[ 9] * b[ 6] + a[13] * b[ 7];
  311. result[ 6] = a[ 1] * b[ 8] + a[ 5] * b[ 9] + a[ 9] * b[10] + a[13] * b[11];
  312. result[ 7] = a[ 1] * b[12] + a[ 5] * b[13] + a[ 9] * b[14] + a[13] * b[15];
  313. result[ 8] = a[ 2] * b[ 0] + a[ 6] * b[ 1] + a[10] * b[ 2] + a[14] * b[ 3];
  314. result[ 9] = a[ 2] * b[ 4] + a[ 6] * b[ 5] + a[10] * b[ 6] + a[14] * b[ 7];
  315. result[10] = a[ 2] * b[ 8] + a[ 6] * b[ 9] + a[10] * b[10] + a[14] * b[11];
  316. result[11] = a[ 2] * b[12] + a[ 6] * b[13] + a[10] * b[14] + a[14] * b[15];
  317. result[12] = a[ 3] * b[ 0] + a[ 7] * b[ 1] + a[11] * b[ 2] + a[15] * b[ 3];
  318. result[13] = a[ 3] * b[ 4] + a[ 7] * b[ 5] + a[11] * b[ 6] + a[15] * b[ 7];
  319. result[14] = a[ 3] * b[ 8] + a[ 7] * b[ 9] + a[11] * b[10] + a[15] * b[11];
  320. result[15] = a[ 3] * b[12] + a[ 7] * b[13] + a[11] * b[14] + a[15] * b[15];
  321. #else
  322. /* Row order */
  323. result[ 0] = a[ 0] * b[ 0] + a[ 1] * b[ 4] + a[ 2] * b[ 8] + a[ 3] * b[12];
  324. result[ 1] = a[ 0] * b[ 1] + a[ 1] * b[ 5] + a[ 2] * b[ 9] + a[ 3] * b[13];
  325. result[ 2] = a[ 0] * b[ 2] + a[ 1] * b[ 6] + a[ 2] * b[10] + a[ 3] * b[14];
  326. result[ 3] = a[ 0] * b[ 3] + a[ 1] * b[ 7] + a[ 2] * b[11] + a[ 3] * b[15];
  327. result[ 4] = a[ 4] * b[ 0] + a[ 5] * b[ 4] + a[ 6] * b[ 8] + a[ 7] * b[12];
  328. result[ 5] = a[ 4] * b[ 1] + a[ 5] * b[ 5] + a[ 6] * b[ 9] + a[ 7] * b[13];
  329. result[ 6] = a[ 4] * b[ 2] + a[ 5] * b[ 6] + a[ 6] * b[10] + a[ 7] * b[14];
  330. result[ 7] = a[ 4] * b[ 3] + a[ 5] * b[ 7] + a[ 6] * b[11] + a[ 7] * b[15];
  331. result[ 8] = a[ 8] * b[ 0] + a[ 9] * b[ 4] + a[10] * b[ 8] + a[11] * b[12];
  332. result[ 9] = a[ 8] * b[ 1] + a[ 9] * b[ 5] + a[10] * b[ 9] + a[11] * b[13];
  333. result[10] = a[ 8] * b[ 2] + a[ 9] * b[ 6] + a[10] * b[10] + a[11] * b[14];
  334. result[11] = a[ 8] * b[ 3] + a[ 9] * b[ 7] + a[10] * b[11] + a[11] * b[15];
  335. result[12] = a[12] * b[ 0] + a[13] * b[ 4] + a[14] * b[ 8] + a[15] * b[12];
  336. result[13] = a[12] * b[ 1] + a[13] * b[ 5] + a[14] * b[ 9] + a[15] * b[13];
  337. result[14] = a[12] * b[ 2] + a[13] * b[ 6] + a[14] * b[10] + a[15] * b[14];
  338. result[15] = a[12] * b[ 3] + a[13] * b[ 7] + a[14] * b[11] + a[15] * b[15];
  339. #endif
  340. }