matrix4.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. const Matrix IDENT_MATRIX = { { 1, 0, 0, 0,
  2. 0, 1, 0, 0,
  3. 0, 0, 1, 0,
  4. 0, 0, 0, 1 } };
  5. void mIdent(Matrix* m) {
  6. *m = IDENT_MATRIX;
  7. }
  8. void mCopy(Matrix* in, Matrix* out) {
  9. *out = *in;
  10. }
  11. // out cannot overlap with a or b
  12. // with restrict and -O2, this vectorizes nicely.
  13. void mFastMul(Matrix* restrict a, Matrix* restrict b, Matrix* restrict out) {
  14. int r, c;
  15. for(r = 0; r < 4; r++) {
  16. for(c = 0; c < 4; c++) {
  17. out->m[c + r * 4] =
  18. (a->m[r * 4 + 0] * b->m[c + 0]) +
  19. (a->m[r * 4 + 1] * b->m[c + 4]) +
  20. (a->m[r * 4 + 2] * b->m[c + 8]) +
  21. (a->m[r * 4 + 3] * b->m[c + 12]);
  22. }
  23. }
  24. }
  25. // out cannot overlap with a. make a copy first if you want to do weird stuff.
  26. void mMul(Matrix* restrict a, Matrix* restrict out) {
  27. Matrix b = *out;
  28. mFastMul(a, &b, out);
  29. }
  30. void mTransv(Vector3* v, Matrix* out) {
  31. mTrans3f(v->x, v->y, v->z, out);
  32. }
  33. void mTrans3f(float x, float y, float z, Matrix* out) {
  34. Matrix t;
  35. t = IDENT_MATRIX;
  36. t.m[12] = x;
  37. t.m[13] = y;
  38. t.m[14] = z;
  39. mMul(&t, out);
  40. }
  41. void mScalev(Vector3* v, Matrix* out) {
  42. mScale3f(v->x, v->y, v->z, out);
  43. }
  44. void mScale3f(float x, float y, float z, Matrix* out) {
  45. Matrix t;
  46. t = IDENT_MATRIX;
  47. t.m[0] = x;
  48. t.m[5] = y;
  49. t.m[10] = z;
  50. mMul(&t, out);
  51. }
  52. void mRotv(Vector3* v, float theta, Matrix* out) {
  53. mRot3f(v->x, v->y, v->z, theta, out);
  54. }
  55. void mRot3f(float x, float y, float z, float theta, Matrix* out) {
  56. float costh, omcosth;
  57. float sinth;
  58. Matrix r;
  59. sincosf(theta, &sinth, &costh);
  60. omcosth = 1 - costh;
  61. r.m[0] = costh + (x * x * omcosth);
  62. r.m[1] = (z * sinth) + (x * y * omcosth);
  63. r.m[2] = (-y * sinth) + (x * z * omcosth);
  64. r.m[3] = 0;
  65. r.m[4] = (x * y * omcosth) - (z * sinth);
  66. r.m[5] = costh + (y * y * omcosth);
  67. r.m[6] = (x * sinth) + (y * z * omcosth);
  68. r.m[7] = 0;
  69. r.m[8] = (y * sinth) + (x * z * omcosth);
  70. r.m[9] = (-x * sinth) + (y * z * omcosth);
  71. r.m[10] = costh + (z * z * omcosth);
  72. r.m[11] = 0;
  73. r.m[12] = 0;
  74. r.m[13] = 0;
  75. r.m[14] = 0;
  76. r.m[15] = 1;
  77. mMul(&r, out);
  78. }
  79. void mRotX(float theta, Matrix* out) {
  80. mRot3f(1,0,0, theta, out);
  81. }
  82. void mRotY(float theta, Matrix* out) {
  83. mRot3f(0,1,0, theta, out);
  84. }
  85. void mRotZ(float theta, Matrix* out) {
  86. mRot3f(0,0,1, theta, out);
  87. }
  88. // removes translation, scale and perspective
  89. void mRotationOnly(Matrix* in, Matrix* out) {
  90. // normalize scale
  91. float invc = 1.f / sqrtf(in->m[0]*in->m[0] + in->m[5]*in->m[5] + in->m[10]*in->m[10] + in->m[15]*in->m[15]);
  92. out->m[0] = in->m[0] * invc;
  93. out->m[5] = in->m[5] * invc;
  94. out->m[10] = in->m[10] * invc;
  95. // perspective
  96. out->m[3] = 0;
  97. out->m[7] = 0;
  98. out->m[11] = 0;
  99. // translation
  100. out->m[12] = 0;
  101. out->m[13] = 0;
  102. out->m[14] = 0;
  103. out->m[15] = 1;
  104. // copy rotation, without scale
  105. out->m[1] = in->m[1] * invc;
  106. out->m[2] = in->m[2] * invc;
  107. out->m[4] = in->m[4] * invc;
  108. out->m[6] = in->m[6] * invc;
  109. out->m[8] = in->m[8] * invc;
  110. out->m[9] = in->m[9] * invc;
  111. }
  112. void mTransposeFast(Matrix* in, Matrix* out) {
  113. int i;
  114. for(i = 0; i < 4; i++) {
  115. out->m[i] = in->m[i * 4];
  116. out->m[i + 4] = in->m[(i * 4) + 1];
  117. out->m[i + 8] = in->m[(i * 4) + 2];
  118. out->m[i + 12] = in->m[(i * 4) + 3];
  119. }
  120. }
  121. void mTranspose(Matrix* in, Matrix* out) {
  122. Matrix t;
  123. mTransposeFast(in, &t);
  124. *out = t;
  125. }
  126. float mTrace(Matrix* m) {
  127. return m->m[0+0*4] + m->m[1+1*4] + m->m[2+2*4] + m->m[3+3*4];
  128. }
  129. void mAdd(Matrix* a, Matrix* b, Matrix* out) {
  130. for(int i = 0; i < 16; i++) {
  131. out->m[i] = a->m[i] + b->m[i];
  132. }
  133. }
  134. void mScalarMul(Matrix* a, float f, Matrix* out) {
  135. for(int i = 0; i < 16; i++) {
  136. out->m[i] = a->m[i] * f;
  137. }
  138. }
  139. float mDeterminate(Matrix* m) {
  140. return
  141. m->m[3] * m->m[6] * m->m[9] * m->m[12] - m->m[2] * m->m[7] * m->m[9] * m->m[12] -
  142. m->m[3] * m->m[5] * m->m[10] * m->m[12] + m->m[1] * m->m[7] * m->m[10] * m->m[12] +
  143. m->m[2] * m->m[5] * m->m[11] * m->m[12] - m->m[1] * m->m[6] * m->m[11] * m->m[12] -
  144. m->m[3] * m->m[6] * m->m[8] * m->m[13] + m->m[2] * m->m[7] * m->m[8] * m->m[13] +
  145. m->m[3] * m->m[4] * m->m[10] * m->m[13] - m->m[0] * m->m[7] * m->m[10] * m->m[13] -
  146. m->m[2] * m->m[4] * m->m[11] * m->m[13] + m->m[0] * m->m[6] * m->m[11] * m->m[13] +
  147. m->m[3] * m->m[5] * m->m[8] * m->m[14] - m->m[1] * m->m[7] * m->m[8] * m->m[14] -
  148. m->m[3] * m->m[4] * m->m[9] * m->m[14] + m->m[0] * m->m[7] * m->m[9] * m->m[14] +
  149. m->m[1] * m->m[4] * m->m[11] * m->m[14] - m->m[0] * m->m[5] * m->m[11] * m->m[14] -
  150. m->m[2] * m->m[5] * m->m[8] * m->m[15] + m->m[1] * m->m[6] * m->m[8] * m->m[15] +
  151. m->m[2] * m->m[4] * m->m[9] * m->m[15] - m->m[0] * m->m[6] * m->m[9] * m->m[15] -
  152. m->m[1] * m->m[4] * m->m[10] * m->m[15] + m->m[0] * m->m[5] * m->m[10] * m->m[15];
  153. }
  154. // shamelessly lifted from this SO post and modified into C, added error checking, and transposed for column major ordering:
  155. // http://stackoverflow.com/a/7596981
  156. // matrix inversions suck. maybe one day i'll lift intel's super fast SSE one instead.
  157. // functions returns 0 if sucessful, 1 if there is no inverse
  158. int mInverse(Matrix* restrict in, Matrix* restrict out) {
  159. float s0, s1, s2, s3, s4, s5;
  160. float c0, c1, c2, c3, c4, c5;
  161. float invdet;
  162. s0 = in->m[0] * in->m[5] - in->m[1] * in->m[4];
  163. s1 = in->m[0] * in->m[9] - in->m[1] * in->m[8];
  164. s2 = in->m[0] * in->m[13] - in->m[1] * in->m[12];
  165. s3 = in->m[4] * in->m[9] - in->m[5] * in->m[8];
  166. s4 = in->m[4] * in->m[13] - in->m[5] * in->m[12];
  167. s5 = in->m[8] * in->m[13] - in->m[9] * in->m[12];
  168. c5 = in->m[10] * in->m[15] - in->m[11] * in->m[14];
  169. c4 = in->m[6] * in->m[15] - in->m[7] * in->m[14];
  170. c3 = in->m[6] * in->m[11] - in->m[7] * in->m[10];
  171. c2 = in->m[2] * in->m[15] - in->m[3] * in->m[14];
  172. c1 = in->m[2] * in->m[11] - in->m[3] * in->m[10];
  173. c0 = in->m[2] * in->m[7] - in->m[3] * in->m[6];
  174. // Should check for 0 determinant
  175. invdet = (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0);
  176. if(invdet == 0.0) {
  177. fprintf(stderr, "ERROR: Matrix has no inverse!!!\n");
  178. *(int*)0 = 1;
  179. return 1;
  180. }
  181. invdet = 1.0 / invdet;
  182. out->m[0] = ( in->m[5] * c5 - in->m[9] * c4 + in->m[13] * c3) * invdet;
  183. out->m[4] = (-in->m[4] * c5 + in->m[8] * c4 - in->m[12] * c3) * invdet;
  184. out->m[8] = ( in->m[7] * s5 - in->m[11] * s4 + in->m[15] * s3) * invdet;
  185. out->m[12] = (-in->m[6] * s5 + in->m[10] * s4 - in->m[14] * s3) * invdet;
  186. out->m[1] = (-in->m[1] * c5 + in->m[9] * c2 - in->m[13] * c1) * invdet;
  187. out->m[5] = ( in->m[0] * c5 - in->m[8] * c2 + in->m[12] * c1) * invdet;
  188. out->m[9] = (-in->m[3] * s5 + in->m[11] * s2 - in->m[15] * s1) * invdet;
  189. out->m[13] = ( in->m[2] * s5 - in->m[10] * s2 + in->m[14] * s1) * invdet;
  190. out->m[2] = ( in->m[1] * c4 - in->m[5] * c2 + in->m[13] * c0) * invdet;
  191. out->m[6] = (-in->m[0] * c4 + in->m[4] * c2 - in->m[12] * c0) * invdet;
  192. out->m[10] = ( in->m[3] * s4 - in->m[7] * s2 + in->m[15] * s0) * invdet;
  193. out->m[14] = (-in->m[2] * s4 + in->m[6] * s2 - in->m[14] * s0) * invdet;
  194. out->m[3] = (-in->m[1] * c3 + in->m[5] * c1 - in->m[9] * c0) * invdet;
  195. out->m[7] = ( in->m[0] * c3 - in->m[4] * c1 + in->m[8] * c0) * invdet;
  196. out->m[11] = (-in->m[3] * s3 + in->m[7] * s1 - in->m[11] * s0) * invdet;
  197. out->m[15] = ( in->m[2] * s3 - in->m[6] * s1 + in->m[10] * s0) * invdet;
  198. return 0;
  199. }
  200. // analogous to glFrustum
  201. // no div/0 checking here for right == left etc. just don't be an idiot.
  202. void mFrustum(float left, float right, float top, float bottom, float near, float far, Matrix* out) {
  203. Matrix m;
  204. m = IDENT_MATRIX;
  205. m.m[0] = (2 * near) / (right - left);
  206. m.m[5] = (2 * near) / (top - bottom);
  207. m.m[8] = (right + left) / (right - left);
  208. m.m[9] = (top + bottom) / (top - bottom);
  209. m.m[10] = -(far + near) / (far - near);
  210. m.m[11] = -1;
  211. m.m[14] = (-2 * far * near) / (far - near);
  212. m.m[15] = 0;
  213. mMul(&m, out);
  214. }
  215. // analogous to gluPerspective
  216. // same div/0 warnings apply. if you get an FP exception you deserve it.
  217. // https://www.opengl.org/archives/resources/faq/technical/transformations.htm
  218. // https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml
  219. void mPerspective(float fov, float aspect, float near, float far, Matrix* out) {
  220. Matrix m;
  221. double f;
  222. m = IDENT_MATRIX;
  223. f = 1.0 / tan(fov * DEG2RAD * .5);
  224. m.m[0] = f / aspect;
  225. m.m[5] = f;
  226. m.m[10] = (far + near) / (near - far);
  227. m.m[11] = -1.0;
  228. m.m[14] = (2.0 * far * near) / (near - far);
  229. m.m[15] = 0.0;
  230. mMul(&m, out);
  231. }
  232. // analogous to gluPerspective
  233. // same div/0 warnings apply. if you get an FP exception you deserve it.
  234. void mPerspectiveVK(float fov, float aspect, float near, float far, Matrix* out) {
  235. *out = IDENT_MATRIX;
  236. float f;
  237. f = 1.0 / tan(fov * DEG2RAD * .5);
  238. out->m[0] = f / aspect;
  239. out->m[5] = -f;
  240. out->m[10] = far / (near - far);
  241. out->m[11] = -1.0;
  242. out->m[14] = (far * near) / (near - far);
  243. out->m[15] = 0.0;
  244. }
  245. // analogous to gluPerspective
  246. // same div/0 warnings apply. if you get an FP exception you deserve it.
  247. void mPerspectiveVK_ZUp(float fov, float aspect, float near, float far, Matrix* out) {
  248. *out = IDENT_MATRIX;
  249. float f;
  250. f = 1.0 / tan(fov * DEG2RAD * .5);
  251. out->m[0] = f / aspect;
  252. out->m[5] = f;
  253. out->m[10] = far / (far - near);
  254. out->m[11] = 1.0;
  255. out->m[14] = -(far * near) / (far - near);
  256. out->m[15] = 0.0;
  257. }
  258. // extract the near and far planes from a prespective matrix
  259. void mPerspExtractNF(Matrix* m, double* near, double* far) {
  260. // perspective computations can be sensitive to precision.
  261. double a = m->m[10];
  262. double b = m->m[14];
  263. *far = b / (1.0f + a);
  264. *near = (-a * b) / (a - 1.0f);
  265. // printf("a: %f, b: %f, f: %f, n: %f\n", a, b, f, n);
  266. }
  267. // extract the near and far planes from a prespective matrix
  268. void mPerspExtractNFVK(Matrix* m, double* near, double* far) {
  269. // perspective computations can be sensitive to precision.
  270. double a = m->m[10]; // = c->far / (c->far - c->near);
  271. double b = m->m[14]; // = -c->near * (c->far / (c->far - c->near));
  272. // per wolfram alpha:
  273. // https://www.wolframalpha.com/input?i=+solve+a+%3D+f+%2F+%28f+-+n%29%2C+b+%3D+-n+*+%28f+%2F+%28f+-+n%29%29+for+n%2C+f
  274. *far = -b / (a - 1.f);
  275. *near = -b / a;
  276. // printf("a: %f, b: %f, f: %f, n: %f\n", a, b, f, n);
  277. }
  278. // set the near and far planes for an existing prespective matrix
  279. void mPerspSetNF_ZUp(Matrix* m, float near, float far) { // Z-up
  280. m->m[6] = (far + near) / (near - far);
  281. m->m[14] = (2.0f * far * near) / (near - far);
  282. }
  283. // set the near and far planes for an existing prespective matrix
  284. void mPerspSetNFVK_ZUp(Matrix* m, float near, float far) { // Z-up
  285. m->m[10] = far / (far - near);
  286. m->m[14] = -(far * near) / (far - near);
  287. }
  288. // set the near and far planes for an existing prespective matrix
  289. void mPerspSetNFVK_ZUp_RDepth(Matrix* m, float near, float far) { // Z-up
  290. m->m[10] = near / (near - far);
  291. m->m[14] = -(near * far) / (near - far);
  292. }
  293. void mPerspSetNF(Matrix* m, float near, float far) { // Y-up
  294. m->m[10] = (far + near) / (far - near);
  295. m->m[14] = (2.0f * far * near) / (far - near);
  296. }
  297. void mPerspSetNFVK(Matrix* m, float near, float far) { // Y-up
  298. m->m[10] = far / (near - far);
  299. m->m[14] = (far * near) / (near - far);
  300. }
  301. void mPerspSetNFVK_RDepth(Matrix* m, float near, float far) { // Y-up
  302. m->m[10] = near / (far - near);
  303. m->m[14] = (near * far) / (far - near);
  304. }
  305. // orthographic projection.
  306. void mOrtho(float left, float right, float top, float bottom, float near, float far, Matrix* out) {
  307. Matrix m;
  308. m = IDENT_MATRIX;
  309. m.m[0] = 2.f / (right - left);
  310. m.m[5] = 2.f / (top - bottom);
  311. m.m[10] = -2.f / (far - near);
  312. m.m[12] = -(right + left) / (right - left);
  313. m.m[13] = -(top + bottom) / (top - bottom);
  314. m.m[14] = -(far + near) / (far - near);
  315. m.m[15] = 1.f;
  316. mMul(&m, out);
  317. }
  318. // orthographic projection.
  319. void mOrthoVK(float left, float right, float top, float bottom, float near, float far, Matrix* out) {
  320. Matrix m;
  321. m = IDENT_MATRIX;
  322. m.m[0] = 2.f / (right - left);
  323. m.m[5] = 2.f / (bottom - top);
  324. m.m[10] = -1.f / (far - near);
  325. m.m[12] = -(right + left) / (right - left);
  326. m.m[13] = -(top + bottom) / (bottom - top);
  327. m.m[14] = near / (near - far); // already at z = 0;
  328. m.m[15] = 1.f;
  329. mMul(&m, out);
  330. }
  331. void mOrthoFromRadius(float r, Matrix* out) {
  332. Matrix m;
  333. float right = -r ;
  334. float left = r;
  335. float top = r;
  336. float bottom = -r;
  337. float near = -r;
  338. float far = r;
  339. *out = IDENT_MATRIX;
  340. out->m[0 + (0*4)] = 2.f / (right - left);
  341. out->m[1 + (1*4)] = 2.f / (top - bottom);
  342. out->m[2 + (2*4)] = -2.f / (far - near);
  343. out->m[0 + (3*4)] = -(top + bottom) / (top - bottom);
  344. out->m[1 + (3*4)] = -(right + left) / (right - left);
  345. out->m[2 + (3*4)] = -(far + near) / (far - near);
  346. out->m[3 + (3*4)] = 1.f;
  347. }
  348. void mOrthoFromRadiusVK(float r, Matrix* out) {
  349. Matrix m;
  350. float right = -r ;
  351. float left = r;
  352. float top = r;
  353. float bottom = -r;
  354. float near = -r;
  355. float far = r;
  356. *out = IDENT_MATRIX;
  357. out->m[0 + (0*4)] = 2.f / (right - left);
  358. out->m[1 + (1*4)] = 2.f / (bottom - top);
  359. out->m[2 + (2*4)] = 1.f / (far - near);
  360. out->m[0 + (3*4)] = -(top + bottom) / (bottom - top);
  361. out->m[1 + (3*4)] = -(right + left) / (right - left);
  362. out->m[2 + (3*4)] = near / (near - far);
  363. out->m[3 + (3*4)] = 1.f;
  364. }
  365. //void mOrthoFromSphere(Sphere* s, Vector3* eyePos, Matrix* out) {
  366. void mOrthoFromSphere(Sphere s, Vector3 eyePos, Vector3 up, Matrix* out) {
  367. Matrix m;
  368. mOrthoFromRadius(s.r, &m);
  369. Vector3 d = vNorm3(vSub3(s.center, eyePos));
  370. Matrix m2;
  371. mLookAt(eyePos, s.center, up, &m2);
  372. mFastMul(&m2, &m, out);
  373. }
  374. //void mOrthoFromSphere(Sphere* s, Vector3* eyePos, Matrix* out) {
  375. void mOrthoFromSphereVK(Sphere s, Vector3 eyePos, Vector3 up, Matrix* out) {
  376. Matrix m;
  377. mOrthoFromRadiusVK(s.r, &m);
  378. Vector3 d = vNorm3(vSub3(s.center, eyePos));
  379. Matrix m2;
  380. mLookAt(eyePos, s.center, up, &m2);
  381. mFastMul(&m2, &m, out);
  382. }
  383. // extract the planes from an orthographic projection matrix.
  384. void mOrthoExtractPlanes(Matrix* m, float* left, float* right, float* top, float* bottom, float* near, float* far) {
  385. *left = (m->m[12] + 1) / -m->m[0];
  386. *right = (-m->m[12] + 1) / m->m[0];
  387. *bottom = (m->m[13] + 1) / m->m[5];
  388. *top = (-m->m[13] + 1) / m->m[5];
  389. *near = (m->m[14] + 1) / m->m[10];
  390. *far = (m->m[14] - 1) / m->m[10];
  391. }
  392. // BUG: probably completely wrong
  393. // extract the planes from an orthographic projection matrix.
  394. void mOrthoExtractPlanesVK(Matrix* m, float* left, float* right, float* top, float* bottom, float* near, float* far) {
  395. *left = (m->m[12] + 1) / -m->m[0];
  396. *right = (-m->m[12] + 1) / m->m[0];
  397. *bottom = (m->m[13] + 1) / m->m[5];
  398. *top = (-m->m[13] + 1) / m->m[5];
  399. *near = (m->m[14] + 1) / m->m[10];
  400. *far = (m->m[14] - 1) / m->m[10];
  401. }
  402. void mOrthoSetNF(Matrix* m, float near, float far) {
  403. m->m[2 + (2*4)] = -2. / (far - near);
  404. m->m[2 + (3*4)] = -(far + near) / (far - near);
  405. }
  406. void mOrthoSetNFVK(Matrix* m, float near, float far) {
  407. m->m[2 + (2*4)] = -1.f / (far - near);
  408. m->m[2 + (3*4)] = -(far + near) / (far - near);
  409. }
  410. // analgous to gluLookAt
  411. // up is not required to be orthogonal to anything, so long as it's not parallel to anything
  412. // http://www.songho.ca/opengl/gl_camera.html#lookat
  413. void mLookAt(Vector3 eye, Vector3 center, Vector3 up, Matrix* out) {
  414. Vector3 forward, left, upn;
  415. Matrix m;
  416. forward = vNorm3(vSub3(eye, center));
  417. left = vNorm3(vCross3(forward, up));
  418. upn = vCross3(left, forward);
  419. m.m[0+(0*4)] = left.x;
  420. m.m[1+(0*4)] = upn.x;
  421. m.m[2+(0*4)] = forward.x;
  422. m.m[3+(0*4)] = 0;
  423. m.m[0+(1*4)] = left.y;
  424. m.m[1+(1*4)] = upn.y;
  425. m.m[2+(1*4)] = forward.y;
  426. m.m[3+(1*4)] = 0;
  427. m.m[0+(2*4)] = left.z;
  428. m.m[1+(2*4)] = upn.z;
  429. m.m[2+(2*4)] = forward.z;
  430. m.m[3+(2*4)] = 0;
  431. m.m[0+(3*4)] = -left.x * center.x - left.y * center.y - left.z * center.z;
  432. m.m[1+(3*4)] = -upn.x * center.x - upn.y * center.y - upn.z * center.z;
  433. m.m[2+(3*4)] = -forward.x * center.x - forward.y * center.y - forward.z * center.z;
  434. m.m[3+(3*4)] = 1;
  435. *out = m;
  436. }
  437. void mLookDir(Vector3 eye, Vector3 dir, Vector3 up, Matrix* out) {
  438. Vector3 forward, left, upn;
  439. Matrix m;
  440. forward = vNeg(dir); //vNorm3(vSub3(eye, center));
  441. left = vNorm3(vCross3(forward, up));
  442. upn = vCross3(left, forward);
  443. m.m[0+(0*4)] = left.x;
  444. m.m[1+(0*4)] = upn.x;
  445. m.m[2+(0*4)] = forward.x;
  446. m.m[3+(0*4)] = 0;
  447. m.m[0+(1*4)] = left.y;
  448. m.m[1+(1*4)] = upn.y;
  449. m.m[2+(1*4)] = forward.y;
  450. m.m[3+(1*4)] = 0;
  451. m.m[0+(2*4)] = left.z;
  452. m.m[1+(2*4)] = upn.z;
  453. m.m[2+(2*4)] = forward.z;
  454. m.m[3+(2*4)] = 0;
  455. m.m[0+(3*4)] = -left.x * eye.x - left.y * eye.y - left.z * eye.z;
  456. m.m[1+(3*4)] = -upn.x * eye.x - upn.y * eye.y - upn.z * eye.z;
  457. m.m[2+(3*4)] = -forward.x * eye.x - forward.y * eye.y - forward.z * eye.z;
  458. m.m[3+(3*4)] = 1;
  459. *out = m;
  460. }
  461. void mRecompose(Vector3* trans, Quaternion* rot, Vector3* scale, Matrix* out) {
  462. Matrix qm;
  463. qUnitToMatrix(*rot, &qm);
  464. *out = IDENT_MATRIX;
  465. mTransv(trans, out);
  466. mMul(&qm, out);
  467. mScalev(scale, out);
  468. }
  469. void mDecompose(Matrix* mat, Vector3* trans, Quaternion* rot, Vector3* scale) {
  470. // translation is just column 3
  471. *trans = (Vector3){mat->m[3*4+0], mat->m[3*4+1], mat->m[3*4+2]};
  472. // scale is extracted out of the rows
  473. float s0 = vLen3((Vector3){mat->m[0*4+0], mat->m[1*4+0], mat->m[2*4+0]});
  474. float s1 = vLen3((Vector3){mat->m[0*4+1], mat->m[1*4+1], mat->m[2*4+1]});
  475. float s2 = vLen3((Vector3){mat->m[0*4+2], mat->m[1*4+2], mat->m[2*4+2]});
  476. // sometimes scale needs to be flipped
  477. float det = mDeterminate(mat);
  478. if(det < 0) s0 = -s0;
  479. scale->x = s0;
  480. scale->y = s1;
  481. scale->z = s2;
  482. float invs0 = 1.0f / s0;
  483. float invs1 = 1.0f / s1;
  484. float invs2 = 1.0f / s2;
  485. // construct a 3x3 rotation mat by dividing out the scale
  486. float m00 = mat->m[0*4+0] * invs0;
  487. float m01 = mat->m[0*4+1] * invs1;
  488. float m02 = mat->m[0*4+2] * invs2;
  489. float m10 = mat->m[1*4+0] * invs0;
  490. float m11 = mat->m[1*4+1] * invs1;
  491. float m12 = mat->m[1*4+2] * invs2;
  492. float m20 = mat->m[2*4+0] * invs0;
  493. float m21 = mat->m[2*4+1] * invs1;
  494. float m22 = mat->m[2*4+2] * invs2;
  495. // there's a nice, small, good paper from Insomniac Games about this algorithm
  496. float t;
  497. if(m22 < 0.f) {
  498. if(m00 > m11) {
  499. t = 1.f + m00 - m11 - m22;
  500. *rot = (Quaternion){t, m01 + m10, m20 + m02, m12 - m21};
  501. }
  502. else {
  503. t = 1.f - m00 + m11 - m22;
  504. *rot = (Quaternion){m01 + m10, t, m12 + m21, m20 - m02};
  505. }
  506. }
  507. else {
  508. if(m00 < -m11) {
  509. t = 1.f - m00 - m11 + m22;
  510. *rot = (Quaternion){m20 + m02, m12 + m21, t, m01 - m10};
  511. }
  512. else {
  513. t = 1.f + m00 + m11 + m22;
  514. *rot = (Quaternion){m12 - m21, m20 - m02, m01 - m10, t};
  515. }
  516. }
  517. vScale4p(rot, 0.5f / sqrtf(t), rot);
  518. }
  519. void mPrint(Matrix* m, FILE* f) {
  520. int r;
  521. if(!f) f = stdout;
  522. for(r = 0; r < 4; r++) {
  523. fprintf(f, "% .3e % .3e % .3e % .3e\n", m->m[r], m->m[r+4], m->m[r+8], m->m[r+12]);
  524. }
  525. fprintf(f, "\n");
  526. }
  527. // make sure you allocate enough. when it's out, it's out. no surprise mallocs later on. (yet)
  528. void msAlloc(int size, MatrixStack* ms) {
  529. ms->stack = (Matrix*)malloc(size * sizeof(Matrix));
  530. ms->size = size;
  531. ms->top = 0;
  532. };
  533. void msFree(MatrixStack* ms) {
  534. free(ms->stack);
  535. ms->stack = NULL;
  536. }
  537. // push a new matrix on the stack. if m is null, push an identity matrix
  538. int msPush(MatrixStack* ms) {
  539. if(ms->top == ms->size - 1) {
  540. fprintf(stderr, "Matrix Stack overflowed.\n");
  541. return 1;
  542. }
  543. ms->top++;
  544. mCopy(&ms->stack[ms->top - 1], &ms->stack[ms->top]);
  545. return 0;
  546. }
  547. void msPop(MatrixStack* ms) {
  548. if(ms->top == 0) return;
  549. ms->top--;
  550. }
  551. Matrix* msGetTop(MatrixStack* ms) {
  552. return &ms->stack[ms->top];
  553. }
  554. void msPrintAll(MatrixStack* ms, FILE* f) {
  555. int i;
  556. if(!f) f = stdout;
  557. for(i = 0; i <= ms->top; i++) {
  558. fprintf(f, "--%3d--------------------------\n", i);
  559. mPrint(&ms->stack[i], f);
  560. }
  561. fprintf(f, "-------------------------------\n");
  562. }
  563. void msIdent(MatrixStack* ms) {
  564. mIdent(msGetTop(ms));
  565. }
  566. void msCopy(Matrix* in, MatrixStack* ms) {
  567. mCopy(in, msGetTop(ms));
  568. }
  569. void msMul(Matrix* a, MatrixStack* ms) { // makes a copy of out before multiplying over it
  570. mMul(a, msGetTop(ms));
  571. }
  572. void msTransv(Vector3* v, MatrixStack* ms) { // translation
  573. mTransv(v, msGetTop(ms));
  574. }
  575. void msTrans3f(float x, float y, float z, MatrixStack* ms) { // translation
  576. mTrans3f(x, y, z, msGetTop(ms));
  577. }
  578. void msScalev(Vector3* v, MatrixStack* ms) {
  579. mScalev(v, msGetTop(ms));
  580. }
  581. void msScale3f(float x, float y, float z, MatrixStack* ms) {
  582. mScale3f(x, y, z, msGetTop(ms));
  583. }
  584. void msRotv(Vector3* v, float theta, MatrixStack* ms) { // rotate about a vector
  585. mRotv(v, theta, msGetTop(ms));
  586. }
  587. void msRot3f(float x, float y, float z, float theta, MatrixStack* ms) { // rotate about a vector
  588. mRot3f(x, y, z, theta, msGetTop(ms));
  589. }
  590. void msFrustum(float left, float right, float top, float bottom, float near, float far, MatrixStack* ms) {
  591. mFrustum(left, right, top, bottom, near, far, msGetTop(ms));
  592. }
  593. void msPerspective(double fov, float aspect, float near, float far, MatrixStack* ms) {
  594. mPerspective(fov, aspect, near, far, msGetTop(ms));
  595. }
  596. void msOrtho(float left, float right, float top, float bottom, float near, float far, MatrixStack* ms) {
  597. mOrtho(left, right, top, bottom, near, far, msGetTop(ms));
  598. }
  599. void msLookAt(Vector3* eye, Vector3* center, Vector3* up, MatrixStack* ms) {
  600. mLookAt(*eye, *center, *up, msGetTop(ms));
  601. }
  602. void msymPlaneFromTrip(Vector3* a, Vector3* b, Vector3* c, MatrixSym* m) {
  603. Vector3 n = vTriFaceNormal3(*a, *b, *c);
  604. float d = vDot3p(&n, a);
  605. m->m[0] = n.x * n.x;
  606. m->m[1] = n.x * n.y;
  607. m->m[2] = n.y * n.y;
  608. m->m[3] = n.x * n.z;
  609. m->m[4] = n.y * n.z;
  610. m->m[5] = n.z * n.z;
  611. m->m[6] = n.x * d;
  612. m->m[7] = n.y * d;
  613. m->m[8] = n.z * d;
  614. m->m[9] = d * d;
  615. }
  616. void msymAddp(MatrixSym* a, MatrixSym* b, MatrixSym* c) {
  617. for(int i = 0; i < 10; i++) c->m[i] = a->m[i] + b->m[i];
  618. }
  619. /*
  620. _ _
  621. | 0 1 3 6 |
  622. | 1 2 4 7 |
  623. | 3 4 5 8 |
  624. |_ 6 7 8 9 _|
  625. */
  626. // v * m * v^t
  627. float msymConjugateMulV3p(MatrixSym* m, Vector3* v) {
  628. float f0 = v->x * m->m[0] + v->x * m->m[1] + v->x * m->m[3] + v->x * m->m[6];
  629. float f1 = v->y * m->m[1] + v->y * m->m[2] + v->y * m->m[4] + v->y * m->m[7];
  630. float f2 = v->z * m->m[3] + v->z * m->m[4] + v->z * m->m[5] + v->z * m->m[8];
  631. float f3 = 1.0 * m->m[6] + 1.0 * m->m[7] + 1.0 * m->m[8] + 1.0 * m->m[9];
  632. return f0 * v->x + f1 * v->y + f2 * v->z + f3 * 1.0;
  633. }