mat4.js 25 KB

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