mat4.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /**
  2. Copyright (c) 2010-2012 cocos2d-x.org
  3. Copyright (c) 2008, Luke Benstead.
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without modification,
  6. are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8. this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation
  11. and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  13. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  16. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  19. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. /*
  24. A 4x4 matrix
  25. mat =
  26. | 0 4 8 12 |
  27. | 1 5 9 13 |
  28. | 2 6 10 14 |
  29. | 3 7 11 15 |
  30. */
  31. cc.kmMat4 = function () {
  32. this.mat = new Float32Array([0, 0, 0, 0,
  33. 0, 0, 0, 0,
  34. 0, 0, 0, 0,
  35. 0, 0, 0, 0]);
  36. };
  37. /**
  38. * Fills a kmMat4 structure with the values from a 16 element array of floats
  39. * @Params pOut - A pointer to the destination matrix
  40. * @Params pMat - A 16 element array of floats
  41. * @Return Returns pOut so that the call can be nested
  42. */
  43. cc.kmMat4Fill = function (pOut, pMat) {
  44. pOut.mat[0] = pOut.mat[1] = pOut.mat[2] =pOut.mat[3] =
  45. pOut.mat[4] =pOut.mat[5] =pOut.mat[6] =pOut.mat[7] =
  46. pOut.mat[8] =pOut.mat[9] =pOut.mat[10] =pOut.mat[11] =
  47. pOut.mat[12] =pOut.mat[13] =pOut.mat[14] =pOut.mat[15] =pMat;
  48. };
  49. /**
  50. * Sets pOut to an identity matrix returns pOut
  51. * @Params pOut - A pointer to the matrix to set to identity
  52. * @Return Returns pOut so that the call can be nested
  53. */
  54. cc.kmMat4Identity = function (pOut) {
  55. pOut.mat[1] = pOut.mat[2] = pOut.mat[3]
  56. = pOut.mat[4] = pOut.mat[6] = pOut.mat[7]
  57. = pOut.mat[8] = pOut.mat[9] = pOut.mat[11]
  58. = pOut.mat[12] = pOut.mat[13] = pOut.mat[14] = 0;
  59. pOut.mat[0] = pOut.mat[5] = pOut.mat[10] = pOut.mat[15] = 1.0;
  60. return pOut;
  61. };
  62. cc.kmMat4._get = function (pIn, row, col) {
  63. return pIn.mat[row + 4 * col];
  64. };
  65. cc.kmMat4._set = function (pIn, row, col, value) {
  66. pIn.mat[row + 4 * col] = value;
  67. };
  68. cc.kmMat4._swap = function (pIn, r1, c1, r2, c2) {
  69. var tmp = cc.kmMat4._get(pIn, r1, c1);
  70. cc.kmMat4._set(pIn, r1, c1, cc.kmMat4._get(pIn, r2, c2));
  71. cc.kmMat4._set(pIn, r2, c2, tmp);
  72. };
  73. //Returns an upper and a lower triangular matrix which are L and R in the Gauss algorithm
  74. cc.kmMat4._gaussj = function (a, b) {
  75. var i, icol = 0, irow = 0, j, k, l, ll, n = 4, m = 4;
  76. var big, dum, pivinv;
  77. var indxc = [0, 0, 0, 0];
  78. var indxr = [0, 0, 0, 0];
  79. var ipiv = [0, 0, 0, 0];
  80. /* for (j = 0; j < n; j++) {
  81. ipiv[j] = 0;
  82. }*/
  83. for (i = 0; i < n; i++) {
  84. big = 0.0;
  85. for (j = 0; j < n; j++) {
  86. if (ipiv[j] != 1) {
  87. for (k = 0; k < n; k++) {
  88. if (ipiv[k] == 0) {
  89. if (Math.abs(cc.kmMat4._get(a, j, k)) >= big) {
  90. big = Math.abs(cc.kmMat4._get(a, j, k));
  91. irow = j;
  92. icol = k;
  93. }
  94. }
  95. }
  96. }
  97. }
  98. ++(ipiv[icol]);
  99. if (irow != icol) {
  100. for (l = 0; l < n; l++)
  101. cc.kmMat4._swap(a, irow, l, icol, l);
  102. for (l = 0; l < m; l++)
  103. cc.kmMat4._swap(b, irow, l, icol, l);
  104. }
  105. indxr[i] = irow;
  106. indxc[i] = icol;
  107. if (cc.kmMat4._get(a, icol, icol) == 0.0)
  108. return cc.KM_FALSE;
  109. pivinv = 1.0 / cc.kmMat4._get(a, icol, icol);
  110. cc.kmMat4._set(a, icol, icol, 1.0);
  111. for (l = 0; l < n; l++)
  112. cc.kmMat4._set(a, icol, l, cc.kmMat4._get(a, icol, l) * pivinv);
  113. for (l = 0; l < m; l++)
  114. cc.kmMat4._set(b, icol, l, cc.kmMat4._get(b, icol, l) * pivinv);
  115. for (ll = 0; ll < n; ll++) {
  116. if (ll != icol) {
  117. dum = cc.kmMat4._get(a, ll, icol);
  118. cc.kmMat4._set(a, ll, icol, 0.0);
  119. for (l = 0; l < n; l++)
  120. cc.kmMat4._set(a, ll, l, cc.kmMat4._get(a, ll, l) - cc.kmMat4._get(a, icol, l) * dum);
  121. for (l = 0; l < m; l++)
  122. cc.kmMat4._set(b, ll, l, cc.kmMat4._get(a, ll, l) - cc.kmMat4._get(b, icol, l) * dum);
  123. }
  124. }
  125. }
  126. // This is the end of the main loop over columns of the reduction. It only remains to unscram-
  127. // ble the solution in view of the column interchanges. We do this by interchanging pairs of
  128. // columns in the reverse order that the permutation was built up.
  129. for (l = n - 1; l >= 0; l--) {
  130. if (indxr[l] != indxc[l]) {
  131. for (k = 0; k < n; k++)
  132. cc.kmMat4._swap(a, k, indxr[l], k, indxc[l]);
  133. }
  134. }
  135. return cc.KM_TRUE;
  136. };
  137. cc.kmMat4._identity =
  138. new Float32Array([1.0, 0.0, 0.0, 0.0,
  139. 0.0, 1.0, 0.0, 0.0,
  140. 0.0, 0.0, 1.0, 0.0,
  141. 0.0, 0.0, 0.0, 1.0]);
  142. /**
  143. * Calculates the inverse of pM and stores the result in
  144. * pOut.
  145. * @Return Returns NULL if there is no inverse, else pOut
  146. */
  147. cc.kmMat4Inverse = function (pOut, pM) {
  148. var inv = new cc.kmMat4();
  149. var tmp = new cc.kmMat4();
  150. cc.kmMat4Assign(inv, pM);
  151. cc.kmMat4Identity(tmp);
  152. if (cc.kmMat4._gaussj(inv, tmp) == cc.KM_FALSE)
  153. return null;
  154. cc.kmMat4Assign(pOut, inv);
  155. return pOut;
  156. };
  157. /**
  158. * Returns KM_TRUE if pIn is an identity matrix
  159. * KM_FALSE otherwise
  160. */
  161. cc.kmMat4IsIdentity = function (pIn) {
  162. for (var i = 0; i < 16; i++) {
  163. if (cc.kmMat4._identity[i] != pIn.mat[i])
  164. return false;
  165. }
  166. return true;
  167. };
  168. /**
  169. * Sets pOut to the transpose of pIn, returns pOut
  170. */
  171. cc.kmMat4Transpose = function (pOut, pIn) {
  172. var x, z, outArr = pOut.mat,inArr = pIn.mat;
  173. for (z = 0; z < 4; ++z) {
  174. for (x = 0; x < 4; ++x)
  175. outArr[(z * 4) + x] = inArr[(x * 4) + z];
  176. }
  177. return pOut;
  178. };
  179. /**
  180. * Multiplies pM1 with pM2, stores the result in pOut, returns pOut
  181. */
  182. cc.kmMat4Multiply = function (pOut, pM1, pM2) {
  183. // Cache the matrix values (makes for huge speed increases!)
  184. var outArray = pOut.mat;
  185. var a00 = pM1.mat[0], a01 = pM1.mat[1], a02 = pM1.mat[2], a03 = pM1.mat[3];
  186. var a10 = pM1.mat[4], a11 = pM1.mat[5], a12 = pM1.mat[6], a13 = pM1.mat[7];
  187. var a20 = pM1.mat[8], a21 = pM1.mat[9], a22 = pM1.mat[10], a23 = pM1.mat[11];
  188. var a30 = pM1.mat[12], a31 = pM1.mat[13], a32 = pM1.mat[14], a33 = pM1.mat[15];
  189. var b00 = pM2.mat[0], b01 = pM2.mat[1], b02 = pM2.mat[2], b03 = pM2.mat[3];
  190. var b10 = pM2.mat[4], b11 = pM2.mat[5], b12 = pM2.mat[6], b13 = pM2.mat[7];
  191. var b20 = pM2.mat[8], b21 = pM2.mat[9], b22 = pM2.mat[10], b23 = pM2.mat[11];
  192. var b30 = pM2.mat[12], b31 = pM2.mat[13], b32 = pM2.mat[14], b33 = pM2.mat[15];
  193. outArray[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
  194. outArray[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
  195. outArray[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
  196. outArray[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
  197. outArray[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
  198. outArray[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
  199. outArray[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
  200. outArray[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
  201. outArray[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
  202. outArray[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
  203. outArray[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
  204. outArray[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
  205. outArray[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
  206. outArray[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
  207. outArray[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
  208. outArray[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
  209. return pOut;
  210. };
  211. cc.getMat4MultiplyValue = function (pM1, pM2) {
  212. var m1 = pM1.mat, m2 = pM2.mat;
  213. var mat = new Float32Array(16);
  214. mat[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
  215. mat[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
  216. mat[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
  217. mat[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
  218. mat[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
  219. mat[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
  220. mat[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
  221. mat[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
  222. mat[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
  223. mat[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
  224. mat[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
  225. mat[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
  226. mat[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
  227. mat[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
  228. mat[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
  229. mat[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
  230. return mat;
  231. };
  232. cc.getMat4MultiplyWithMat4 = function (pM1, pM2, swapMat) {
  233. var m1 = pM1.mat, m2 = pM2.mat;
  234. var mat = swapMat.mat;
  235. mat[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
  236. mat[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
  237. mat[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
  238. mat[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
  239. mat[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
  240. mat[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
  241. mat[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
  242. mat[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
  243. mat[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
  244. mat[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
  245. mat[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
  246. mat[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
  247. mat[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
  248. mat[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
  249. mat[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
  250. mat[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
  251. return swapMat.mat;
  252. };
  253. /**
  254. * Assigns the value of pIn to pOut
  255. */
  256. cc.kmMat4Assign = function (pOut, pIn) {
  257. if(pOut == pIn) {
  258. cc.log("cc.kmMat4Assign(): pOut equals pIn");
  259. return pOut;
  260. }
  261. var outArr = pOut.mat;
  262. var inArr = pIn.mat;
  263. outArr[0] = inArr[0];
  264. outArr[1] = inArr[1];
  265. outArr[2] = inArr[2];
  266. outArr[3] = inArr[3];
  267. outArr[4] = inArr[4];
  268. outArr[5] = inArr[5];
  269. outArr[6] = inArr[6];
  270. outArr[7] = inArr[7];
  271. outArr[8] = inArr[8];
  272. outArr[9] = inArr[9];
  273. outArr[10] = inArr[10];
  274. outArr[11] = inArr[11];
  275. outArr[12] = inArr[12];
  276. outArr[13] = inArr[13];
  277. outArr[14] = inArr[14];
  278. outArr[15] = inArr[15];
  279. return pOut;
  280. };
  281. /**
  282. * Returns KM_TRUE if the 2 matrices are equal (approximately)
  283. */
  284. cc.kmMat4AreEqual = function (pMat1, pMat2) {
  285. if(pMat1 == pMat2){
  286. cc.log("cc.kmMat4AreEqual(): pMat1 and pMat2 are same object.");
  287. return true;
  288. }
  289. for (var i = 0; i < 16; i++) {
  290. if (!(pMat1.mat[i] + cc.kmEpsilon > pMat2.mat[i] &&
  291. pMat1.mat[i] - cc.kmEpsilon < pMat2.mat[i])) {
  292. return false;
  293. }
  294. }
  295. return true;
  296. };
  297. /**
  298. * Builds an X-axis rotation matrix and stores it in pOut, returns pOut
  299. */
  300. cc.kmMat4RotationX = function (pOut, radians) {
  301. /*
  302. | 1 0 0 0 |
  303. M = | 0 cos(A) -sin(A) 0 |
  304. | 0 sin(A) cos(A) 0 |
  305. | 0 0 0 1 |
  306. */
  307. pOut.mat[0] = 1.0;
  308. pOut.mat[1] = 0.0;
  309. pOut.mat[2] = 0.0;
  310. pOut.mat[3] = 0.0;
  311. pOut.mat[4] = 0.0;
  312. pOut.mat[5] = Math.cos(radians);
  313. pOut.mat[6] = Math.sin(radians);
  314. pOut.mat[7] = 0.0;
  315. pOut.mat[8] = 0.0;
  316. pOut.mat[9] = -Math.sin(radians);
  317. pOut.mat[10] = Math.cos(radians);
  318. pOut.mat[11] = 0.0;
  319. pOut.mat[12] = 0.0;
  320. pOut.mat[13] = 0.0;
  321. pOut.mat[14] = 0.0;
  322. pOut.mat[15] = 1.0;
  323. return pOut;
  324. };
  325. /**
  326. * Builds a rotation matrix using the rotation around the Y-axis
  327. * The result is stored in pOut, pOut is returned.
  328. */
  329. cc.kmMat4RotationY = function (pOut, radians) {
  330. /*
  331. | cos(A) 0 sin(A) 0 |
  332. M = | 0 1 0 0 |
  333. | -sin(A) 0 cos(A) 0 |
  334. | 0 0 0 1 |
  335. */
  336. pOut.mat[0] = Math.cos(radians);
  337. pOut.mat[1] = 0.0;
  338. pOut.mat[2] = -Math.sin(radians);
  339. pOut.mat[3] = 0.0;
  340. pOut.mat[4] = 0.0;
  341. pOut.mat[5] = 1.0;
  342. pOut.mat[6] = 0.0;
  343. pOut.mat[7] = 0.0;
  344. pOut.mat[8] = Math.sin(radians);
  345. pOut.mat[9] = 0.0;
  346. pOut.mat[10] = Math.cos(radians);
  347. pOut.mat[11] = 0.0;
  348. pOut.mat[12] = 0.0;
  349. pOut.mat[13] = 0.0;
  350. pOut.mat[14] = 0.0;
  351. pOut.mat[15] = 1.0;
  352. return pOut;
  353. };
  354. /**
  355. * Builds a rotation matrix around the Z-axis. The resulting
  356. * matrix is stored in pOut. pOut is returned.
  357. */
  358. cc.kmMat4RotationZ = function (pOut, radians) {
  359. /*
  360. | cos(A) -sin(A) 0 0 |
  361. M = | sin(A) cos(A) 0 0 |
  362. | 0 0 1 0 |
  363. | 0 0 0 1 |
  364. */
  365. pOut.mat[0] = Math.cos(radians);
  366. pOut.mat[1] = Math.sin(radians);
  367. pOut.mat[2] = 0.0;
  368. pOut.mat[3] = 0.0;
  369. pOut.mat[4] = -Math.sin(radians);
  370. pOut.mat[5] = Math.cos(radians);
  371. pOut.mat[6] = 0.0;
  372. pOut.mat[7] = 0.0;
  373. pOut.mat[8] = 0.0;
  374. pOut.mat[9] = 0.0;
  375. pOut.mat[10] = 1.0;
  376. pOut.mat[11] = 0.0;
  377. pOut.mat[12] = 0.0;
  378. pOut.mat[13] = 0.0;
  379. pOut.mat[14] = 0.0;
  380. pOut.mat[15] = 1.0;
  381. return pOut;
  382. };
  383. /**
  384. * Builds a rotation matrix from pitch, yaw and roll. The resulting
  385. * matrix is stored in pOut and pOut is returned
  386. */
  387. cc.kmMat4RotationPitchYawRoll = function (pOut, pitch, yaw, roll) {
  388. var cr = Math.cos(pitch);
  389. var sr = Math.sin(pitch);
  390. var cp = Math.cos(yaw);
  391. var sp = Math.sin(yaw);
  392. var cy = Math.cos(roll);
  393. var sy = Math.sin(roll);
  394. var srsp = sr * sp;
  395. var crsp = cr * sp;
  396. pOut.mat[0] = cp * cy;
  397. pOut.mat[4] = cp * sy;
  398. pOut.mat[8] = -sp;
  399. pOut.mat[1] = srsp * cy - cr * sy;
  400. pOut.mat[5] = srsp * sy + cr * cy;
  401. pOut.mat[9] = sr * cp;
  402. pOut.mat[2] = crsp * cy + sr * sy;
  403. pOut.mat[6] = crsp * sy - sr * cy;
  404. pOut.mat[10] = cr * cp;
  405. pOut.mat[3] = pOut.mat[7] = pOut.mat[11] = 0.0;
  406. pOut.mat[15] = 1.0;
  407. return pOut;
  408. };
  409. /** Converts a quaternion to a rotation matrix,
  410. * the result is stored in pOut, returns pOut
  411. */
  412. cc.kmMat4RotationQuaternion = function (pOut, pQ) {
  413. pOut.mat[0] = 1.0 - 2.0 * (pQ.y * pQ.y + pQ.z * pQ.z );
  414. pOut.mat[1] = 2.0 * (pQ.x * pQ.y + pQ.z * pQ.w);
  415. pOut.mat[2] = 2.0 * (pQ.x * pQ.z - pQ.y * pQ.w);
  416. pOut.mat[3] = 0.0;
  417. // Second row
  418. pOut.mat[4] = 2.0 * ( pQ.x * pQ.y - pQ.z * pQ.w );
  419. pOut.mat[5] = 1.0 - 2.0 * ( pQ.x * pQ.x + pQ.z * pQ.z );
  420. pOut.mat[6] = 2.0 * (pQ.z * pQ.y + pQ.x * pQ.w );
  421. pOut.mat[7] = 0.0;
  422. // Third row
  423. pOut.mat[8] = 2.0 * ( pQ.x * pQ.z + pQ.y * pQ.w );
  424. pOut.mat[9] = 2.0 * ( pQ.y * pQ.z - pQ.x * pQ.w );
  425. pOut.mat[10] = 1.0 - 2.0 * ( pQ.x * pQ.x + pQ.y * pQ.y );
  426. pOut.mat[11] = 0.0;
  427. // Fourth row
  428. pOut.mat[12] = 0;
  429. pOut.mat[13] = 0;
  430. pOut.mat[14] = 0;
  431. pOut.mat[15] = 1.0;
  432. return pOut;
  433. };
  434. /** Build a 4x4 OpenGL transformation matrix using a 3x3 rotation matrix,
  435. * and a 3d vector representing a translation. Assign the result to pOut,
  436. * pOut is also returned.
  437. */
  438. cc.kmMat4RotationTranslation = function (pOut, rotation, translation) {
  439. pOut.mat[0] = rotation.mat[0];
  440. pOut.mat[1] = rotation.mat[1];
  441. pOut.mat[2] = rotation.mat[2];
  442. pOut.mat[3] = 0.0;
  443. pOut.mat[4] = rotation.mat[3];
  444. pOut.mat[5] = rotation.mat[4];
  445. pOut.mat[6] = rotation.mat[5];
  446. pOut.mat[7] = 0.0;
  447. pOut.mat[8] = rotation.mat[6];
  448. pOut.mat[9] = rotation.mat[7];
  449. pOut.mat[10] = rotation.mat[8];
  450. pOut.mat[11] = 0.0;
  451. pOut.mat[12] = translation.x;
  452. pOut.mat[13] = translation.y;
  453. pOut.mat[14] = translation.z;
  454. pOut.mat[15] = 1.0;
  455. return pOut;
  456. };
  457. /** Builds a scaling matrix */
  458. cc.kmMat4Scaling = function (pOut, x, y, z) {
  459. pOut.mat[0] = x;
  460. pOut.mat[5] = y;
  461. pOut.mat[10] = z;
  462. pOut.mat[15] = 1.0;
  463. pOut.mat[1] = pOut.mat[2] = pOut.mat[3] =
  464. pOut.mat[4] = pOut.mat[6] = pOut.mat[7] =
  465. pOut.mat[8] = pOut.mat[9] = pOut.mat[11] =
  466. pOut.mat[12] = pOut.mat[13] = pOut.mat[14] = 0;
  467. return pOut;
  468. };
  469. /**
  470. * Builds a translation matrix. All other elements in the matrix
  471. * will be set to zero except for the diagonal which is set to 1.0
  472. */
  473. cc.kmMat4Translation = function (pOut, x, y, z) {
  474. //FIXME: Write a test for this
  475. pOut.mat[0] = pOut.mat[5] = pOut.mat[10] = pOut.mat[15] = 1.0;
  476. pOut.mat[1] = pOut.mat[2] = pOut.mat[3] =
  477. pOut.mat[4] = pOut.mat[6] = pOut.mat[7] =
  478. pOut.mat[8] = pOut.mat[9] = pOut.mat[11] = 0.0;
  479. pOut.mat[12] = x;
  480. pOut.mat[13] = y;
  481. pOut.mat[14] = z;
  482. return pOut;
  483. };
  484. /**
  485. * Get the up vector from a matrix. pIn is the matrix you
  486. * wish to extract the vector from. pOut is a pointer to the
  487. * kmVec3 structure that should hold the resulting vector
  488. */
  489. cc.kmMat4GetUpVec3 = function (pOut, pIn) {
  490. pOut.x = pIn.mat[4];
  491. pOut.y = pIn.mat[5];
  492. pOut.z = pIn.mat[6];
  493. cc.kmVec3Normalize(pOut, pOut);
  494. return pOut;
  495. };
  496. /** Extract the right vector from a 4x4 matrix. The result is
  497. * stored in pOut. Returns pOut.
  498. */
  499. cc.kmMat4GetRightVec3 = function (pOut, pIn) {
  500. pOut.x = pIn.mat[0];
  501. pOut.y = pIn.mat[1];
  502. pOut.z = pIn.mat[2];
  503. cc.kmVec3Normalize(pOut, pOut);
  504. return pOut;
  505. };
  506. /**
  507. * Extract the forward vector from a 4x4 matrix. The result is
  508. * stored in pOut. Returns pOut.
  509. */
  510. cc.kmMat4GetForwardVec3 = function (pOut, pIn) {
  511. pOut.x = pIn.mat[8];
  512. pOut.y = pIn.mat[9];
  513. pOut.z = pIn.mat[10];
  514. cc.kmVec3Normalize(pOut, pOut);
  515. return pOut;
  516. };
  517. /**
  518. * Creates a perspective projection matrix in the
  519. * same way as gluPerspective
  520. */
  521. cc.kmMat4PerspectiveProjection = function (pOut, fovY, aspect, zNear, zFar) {
  522. var r = cc.kmDegreesToRadians(fovY / 2);
  523. var deltaZ = zFar - zNear;
  524. var s = Math.sin(r);
  525. if (deltaZ == 0 || s == 0 || aspect == 0)
  526. return null;
  527. //cos(r) / sin(r) = cot(r)
  528. var cotangent = Math.cos(r) / s;
  529. cc.kmMat4Identity(pOut);
  530. pOut.mat[0] = cotangent / aspect;
  531. pOut.mat[5] = cotangent;
  532. pOut.mat[10] = -(zFar + zNear) / deltaZ;
  533. pOut.mat[11] = -1;
  534. pOut.mat[14] = -2 * zNear * zFar / deltaZ;
  535. pOut.mat[15] = 0;
  536. return pOut;
  537. };
  538. /** Creates an orthographic projection matrix like glOrtho */
  539. cc.kmMat4OrthographicProjection = function (pOut, left, right, bottom, top, nearVal, farVal) {
  540. cc.kmMat4Identity(pOut);
  541. pOut.mat[0] = 2 / (right - left);
  542. pOut.mat[5] = 2 / (top - bottom);
  543. pOut.mat[10] = -2 / (farVal - nearVal);
  544. pOut.mat[12] = -((right + left) / (right - left));
  545. pOut.mat[13] = -((top + bottom) / (top - bottom));
  546. pOut.mat[14] = -((farVal + nearVal) / (farVal - nearVal));
  547. return pOut;
  548. };
  549. /**
  550. * Builds a translation matrix in the same way as gluLookAt()
  551. * the resulting matrix is stored in pOut. pOut is returned.
  552. */
  553. cc.kmMat4LookAt = function (pOut, pEye, pCenter, pUp) {
  554. var f = new cc.kmVec3(), up = new cc.kmVec3(), s = new cc.kmVec3(), u = new cc.kmVec3();
  555. var translate = new cc.kmMat4();
  556. cc.kmVec3Subtract(f, pCenter, pEye);
  557. cc.kmVec3Normalize(f, f);
  558. cc.kmVec3Assign(up, pUp);
  559. cc.kmVec3Normalize(up, up);
  560. cc.kmVec3Cross(s, f, up);
  561. cc.kmVec3Normalize(s, s);
  562. cc.kmVec3Cross(u, s, f);
  563. cc.kmVec3Normalize(s, s);
  564. cc.kmMat4Identity(pOut);
  565. pOut.mat[0] = s.x;
  566. pOut.mat[4] = s.y;
  567. pOut.mat[8] = s.z;
  568. pOut.mat[1] = u.x;
  569. pOut.mat[5] = u.y;
  570. pOut.mat[9] = u.z;
  571. pOut.mat[2] = -f.x;
  572. pOut.mat[6] = -f.y;
  573. pOut.mat[10] = -f.z;
  574. cc.kmMat4Translation(translate, -pEye.x, -pEye.y, -pEye.z);
  575. cc.kmMat4Multiply(pOut, pOut, translate);
  576. return pOut;
  577. };
  578. /**
  579. * Build a rotation matrix from an axis and an angle. Result is stored in pOut.
  580. * pOut is returned.
  581. */
  582. cc.kmMat4RotationAxisAngle = function (pOut, axis, radians) {
  583. var rcos = Math.cos(radians);
  584. var rsin = Math.sin(radians);
  585. var normalizedAxis = new cc.kmVec3();
  586. cc.kmVec3Normalize(normalizedAxis, axis);
  587. pOut.mat[0] = rcos + normalizedAxis.x * normalizedAxis.x * (1 - rcos);
  588. pOut.mat[1] = normalizedAxis.z * rsin + normalizedAxis.y * normalizedAxis.x * (1 - rcos);
  589. pOut.mat[2] = -normalizedAxis.y * rsin + normalizedAxis.z * normalizedAxis.x * (1 - rcos);
  590. pOut.mat[3] = 0.0;
  591. pOut.mat[4] = -normalizedAxis.z * rsin + normalizedAxis.x * normalizedAxis.y * (1 - rcos);
  592. pOut.mat[5] = rcos + normalizedAxis.y * normalizedAxis.y * (1 - rcos);
  593. pOut.mat[6] = normalizedAxis.x * rsin + normalizedAxis.z * normalizedAxis.y * (1 - rcos);
  594. pOut.mat[7] = 0.0;
  595. pOut.mat[8] = normalizedAxis.y * rsin + normalizedAxis.x * normalizedAxis.z * (1 - rcos);
  596. pOut.mat[9] = -normalizedAxis.x * rsin + normalizedAxis.y * normalizedAxis.z * (1 - rcos);
  597. pOut.mat[10] = rcos + normalizedAxis.z * normalizedAxis.z * (1 - rcos);
  598. pOut.mat[11] = 0.0;
  599. pOut.mat[12] = 0.0;
  600. pOut.mat[13] = 0.0;
  601. pOut.mat[14] = 0.0;
  602. pOut.mat[15] = 1.0;
  603. return pOut;
  604. };
  605. /**
  606. * Extract a 3x3 rotation matrix from the input 4x4 transformation.
  607. * Stores the result in pOut, returns pOut
  608. */
  609. cc.kmMat4ExtractRotation = function (pOut, pIn) {
  610. pOut.mat[0] = pIn.mat[0];
  611. pOut.mat[1] = pIn.mat[1];
  612. pOut.mat[2] = pIn.mat[2];
  613. pOut.mat[3] = pIn.mat[4];
  614. pOut.mat[4] = pIn.mat[5];
  615. pOut.mat[5] = pIn.mat[6];
  616. pOut.mat[6] = pIn.mat[8];
  617. pOut.mat[7] = pIn.mat[9];
  618. pOut.mat[8] = pIn.mat[10];
  619. return pOut;
  620. };
  621. cc.kmMat4ExtractPlane = function (pOut, pIn, plane) {
  622. switch (plane) {
  623. case cc.KM_PLANE_RIGHT:
  624. pOut.a = pIn.mat[3] - pIn.mat[0];
  625. pOut.b = pIn.mat[7] - pIn.mat[4];
  626. pOut.c = pIn.mat[11] - pIn.mat[8];
  627. pOut.d = pIn.mat[15] - pIn.mat[12];
  628. break;
  629. case cc.KM_PLANE_LEFT:
  630. pOut.a = pIn.mat[3] + pIn.mat[0];
  631. pOut.b = pIn.mat[7] + pIn.mat[4];
  632. pOut.c = pIn.mat[11] + pIn.mat[8];
  633. pOut.d = pIn.mat[15] + pIn.mat[12];
  634. break;
  635. case cc.KM_PLANE_BOTTOM:
  636. pOut.a = pIn.mat[3] + pIn.mat[1];
  637. pOut.b = pIn.mat[7] + pIn.mat[5];
  638. pOut.c = pIn.mat[11] + pIn.mat[9];
  639. pOut.d = pIn.mat[15] + pIn.mat[13];
  640. break;
  641. case cc.KM_PLANE_TOP:
  642. pOut.a = pIn.mat[3] - pIn.mat[1];
  643. pOut.b = pIn.mat[7] - pIn.mat[5];
  644. pOut.c = pIn.mat[11] - pIn.mat[9];
  645. pOut.d = pIn.mat[15] - pIn.mat[13];
  646. break;
  647. case cc.KM_PLANE_FAR:
  648. pOut.a = pIn.mat[3] - pIn.mat[2];
  649. pOut.b = pIn.mat[7] - pIn.mat[6];
  650. pOut.c = pIn.mat[11] - pIn.mat[10];
  651. pOut.d = pIn.mat[15] - pIn.mat[14];
  652. break;
  653. case cc.KM_PLANE_NEAR:
  654. pOut.a = pIn.mat[3] + pIn.mat[2];
  655. pOut.b = pIn.mat[7] + pIn.mat[6];
  656. pOut.c = pIn.mat[11] + pIn.mat[10];
  657. pOut.d = pIn.mat[15] + pIn.mat[14];
  658. break;
  659. default:
  660. cc.log("cc.kmMat4ExtractPlane(): Invalid plane index");
  661. break;
  662. }
  663. var t = Math.sqrt(pOut.a * pOut.a +
  664. pOut.b * pOut.b +
  665. pOut.c * pOut.c);
  666. pOut.a /= t;
  667. pOut.b /= t;
  668. pOut.c /= t;
  669. pOut.d /= t;
  670. return pOut;
  671. };
  672. /**
  673. * Take the rotation from a 4x4 transformation matrix, and return it as an axis and an angle (in radians)
  674. * returns the output axis.
  675. */
  676. cc.kmMat4RotationToAxisAngle = function (pAxis, radians, pIn) {
  677. /*Surely not this easy?*/
  678. var temp = new cc.kmQuaternion();
  679. var rotation = new cc.kmMat3();
  680. cc.kmMat4ExtractRotation(rotation, pIn);
  681. cc.kmQuaternionRotationMatrix(temp, rotation);
  682. cc.kmQuaternionToAxisAngle(temp, pAxis, radians);
  683. return pAxis;
  684. };