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

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