specific.odin 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. package linalg
  2. import "core:math"
  3. import "intrinsics"
  4. // Specific
  5. Float :: f32;
  6. FLOAT_EPSILON :: size_of(Float) == 4 ? 1e-7 : 1e-15;
  7. Vector2 :: distinct [2]Float;
  8. Vector3 :: distinct [3]Float;
  9. Vector4 :: distinct [4]Float;
  10. Matrix1x1 :: distinct [1][1]Float;
  11. Matrix1x2 :: distinct [1][2]Float;
  12. Matrix1x3 :: distinct [1][3]Float;
  13. Matrix1x4 :: distinct [1][4]Float;
  14. Matrix2x1 :: distinct [2][1]Float;
  15. Matrix2x2 :: distinct [2][2]Float;
  16. Matrix2x3 :: distinct [2][3]Float;
  17. Matrix2x4 :: distinct [2][4]Float;
  18. Matrix3x1 :: distinct [3][1]Float;
  19. Matrix3x2 :: distinct [3][2]Float;
  20. Matrix3x3 :: distinct [3][3]Float;
  21. Matrix3x4 :: distinct [3][4]Float;
  22. Matrix4x1 :: distinct [4][1]Float;
  23. Matrix4x2 :: distinct [4][2]Float;
  24. Matrix4x3 :: distinct [4][3]Float;
  25. Matrix4x4 :: distinct [4][4]Float;
  26. Matrix1 :: Matrix1x1;
  27. Matrix2 :: Matrix2x2;
  28. Matrix3 :: Matrix3x3;
  29. Matrix4 :: Matrix4x4;
  30. Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256);
  31. MATRIX1_IDENTITY :: Matrix1{{1}};
  32. MATRIX2_IDENTITY :: Matrix2{{1, 0}, {0, 1}};
  33. MATRIX3_IDENTITY :: Matrix3{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
  34. MATRIX4_IDENTITY :: Matrix4{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
  35. QUATERNION_IDENTITY :: Quaternion(1);
  36. VECTOR3_X_AXIS :: Vector3{1, 0, 0};
  37. VECTOR3_Y_AXIS :: Vector3{0, 1, 0};
  38. VECTOR3_Z_AXIS :: Vector3{0, 0, 1};
  39. radians :: proc(degrees: Float) -> Float {
  40. return math.TAU * degrees / 360.0;
  41. }
  42. degrees :: proc(radians: Float) -> Float {
  43. return 360.0 * radians / math.TAU;
  44. }
  45. vector2_orthogonal :: proc(v: Vector2) -> Vector2 {
  46. return {-v.y, v.x};
  47. }
  48. vector3_orthogonal :: proc(v: Vector3) -> Vector3 {
  49. x := abs(v.x);
  50. y := abs(v.y);
  51. z := abs(v.z);
  52. other: Vector3 = x < y ? (x < z ? {1, 0, 0} : {0, 0, 1}) : (y < z ? {0, 1, 0} : {0, 0, 1});
  53. return normalize(cross(v, other));
  54. }
  55. vector4_srgb_to_linear :: proc(col: Vector4) -> Vector4 {
  56. r := math.pow(col.x, 2.2);
  57. g := math.pow(col.y, 2.2);
  58. b := math.pow(col.z, 2.2);
  59. a := col.w;
  60. return {r, g, b, a};
  61. }
  62. vector4_linear_to_srgb :: proc(col: Vector4) -> Vector4 {
  63. a :: 2.51;
  64. b :: 0.03;
  65. c :: 2.43;
  66. d :: 0.59;
  67. e :: 0.14;
  68. x := col.x;
  69. y := col.y;
  70. z := col.z;
  71. x = (x * (a * x + b)) / (x * (c * x + d) + e);
  72. y = (y * (a * y + b)) / (y * (c * y + d) + e);
  73. z = (z * (a * z + b)) / (z * (c * z + d) + e);
  74. x = math.pow(clamp(x, 0, 1), 1.0 / 2.2);
  75. y = math.pow(clamp(y, 0, 1), 1.0 / 2.2);
  76. z = math.pow(clamp(z, 0, 1), 1.0 / 2.2);
  77. return {x, y, z, col.w};
  78. }
  79. vector4_hsl_to_rgb :: proc(h, s, l: Float, a: Float = 1) -> Vector4 {
  80. hue_to_rgb :: proc(p, q, t0: Float) -> Float {
  81. t := math.mod(t0, 1.0);
  82. switch {
  83. case t < 1.0/6.0: return p + (q - p) * 6.0 * t;
  84. case t < 1.0/2.0: return q;
  85. case t < 2.0/3.0: return p + (q - p) * 6.0 * (2.0/3.0 - t);
  86. }
  87. return p;
  88. }
  89. r, g, b: Float;
  90. if s == 0 {
  91. r = l;
  92. g = l;
  93. b = l;
  94. } else {
  95. q := l < 0.5 ? l * (1+s) : l+s - l*s;
  96. p := 2*l - q;
  97. r = hue_to_rgb(p, q, h + 1.0/3.0);
  98. g = hue_to_rgb(p, q, h);
  99. b = hue_to_rgb(p, q, h - 1.0/3.0);
  100. }
  101. return {r, g, b, a};
  102. }
  103. vector4_rgb_to_hsl :: proc(col: Vector4) -> Vector4 {
  104. r := col.x;
  105. g := col.y;
  106. b := col.z;
  107. a := col.w;
  108. v_min := min(r, g, b);
  109. v_max := max(r, g, b);
  110. h, s, l: Float;
  111. h = 0.0;
  112. s = 0.0;
  113. l = (v_min + v_max) * 0.5;
  114. if v_max != v_min {
  115. d: = v_max - v_min;
  116. s = l > 0.5 ? d / (2.0 - v_max - v_min) : d / (v_max + v_min);
  117. switch {
  118. case v_max == r:
  119. h = (g - b) / d + (g < b ? 6.0 : 0.0);
  120. case v_max == g:
  121. h = (b - r) / d + 2.0;
  122. case v_max == b:
  123. h = (r - g) / d + 4.0;
  124. }
  125. h *= 1.0/6.0;
  126. }
  127. return {h, s, l, a};
  128. }
  129. quaternion_angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion {
  130. t := angle_radians*0.5;
  131. w := math.cos(t);
  132. v := normalize(axis) * math.sin(t);
  133. return quaternion(w, v.x, v.y, v.z);
  134. }
  135. quaternion_from_euler_angles :: proc(roll, pitch, yaw: Float) -> Quaternion {
  136. x, y, z := roll, pitch, yaw;
  137. a, b, c := x, y, z;
  138. ca, sa := math.cos(a*0.5), math.sin(a*0.5);
  139. cb, sb := math.cos(b*0.5), math.sin(b*0.5);
  140. cc, sc := math.cos(c*0.5), math.sin(c*0.5);
  141. q: Quaternion;
  142. q.x = sa*cb*cc - ca*sb*sc;
  143. q.y = ca*sb*cc + sa*cb*sc;
  144. q.z = ca*cb*sc - sa*sb*cc;
  145. q.w = ca*cb*cc + sa*sb*sc;
  146. return q;
  147. }
  148. euler_angles_from_quaternion :: proc(q: Quaternion) -> (roll, pitch, yaw: Float) {
  149. // roll, x-axis rotation
  150. sinr_cosp: Float = 2 * (q.w * q.x + q.y * q.z);
  151. cosr_cosp: Float = 1 - 2 * (q.x * q.x + q.y * q.y);
  152. roll = math.atan2(sinr_cosp, cosr_cosp);
  153. // pitch, y-axis rotation
  154. sinp: Float = 2 * (q.w * q.y - q.z * q.x);
  155. if abs(sinp) >= 1 {
  156. pitch = math.copy_sign(math.TAU * 0.25, sinp);
  157. } else {
  158. pitch = math.asin(sinp);
  159. }
  160. // yaw, z-axis rotation
  161. siny_cosp: Float = 2 * (q.w * q.z + q.x * q.y);
  162. cosy_cosp: Float = 1 - 2 * (q.y * q.y + q.z * q.z);
  163. yaw = math.atan2(siny_cosp, cosy_cosp);
  164. return;
  165. }
  166. quaternion_from_forward_and_up :: proc(forward, up: Vector3) -> Quaternion {
  167. f := normalize(forward);
  168. s := normalize(cross(f, up));
  169. u := cross(s, f);
  170. m := Matrix3{
  171. {+s.x, +u.x, -f.x},
  172. {+s.y, +u.y, -f.y},
  173. {+s.z, +u.z, -f.z},
  174. };
  175. tr := trace(m);
  176. q: Quaternion;
  177. switch {
  178. case tr > 0:
  179. S := 2 * math.sqrt(1 + tr);
  180. q.w = 0.25 * S;
  181. q.x = (m[2][1] - m[1][2]) / S;
  182. q.y = (m[0][2] - m[2][0]) / S;
  183. q.z = (m[1][0] - m[0][1]) / S;
  184. case (m[0][0] > m[1][1]) && (m[0][0] > m[2][2]):
  185. S := 2 * math.sqrt(1 + m[0][0] - m[1][1] - m[2][2]);
  186. q.w = (m[2][1] - m[1][2]) / S;
  187. q.x = 0.25 * S;
  188. q.y = (m[0][1] + m[1][0]) / S;
  189. q.z = (m[0][2] + m[2][0]) / S;
  190. case m[1][1] > m[2][2]:
  191. S := 2 * math.sqrt(1 + m[1][1] - m[0][0] - m[2][2]);
  192. q.w = (m[0][2] - m[2][0]) / S;
  193. q.x = (m[0][1] + m[1][0]) / S;
  194. q.y = 0.25 * S;
  195. q.z = (m[1][2] + m[2][1]) / S;
  196. case:
  197. S := 2 * math.sqrt(1 + m[2][2] - m[0][0] - m[1][1]);
  198. q.w = (m[1][0] - m[0][1]) / S;
  199. q.x = (m[0][2] - m[2][0]) / S;
  200. q.y = (m[1][2] + m[2][1]) / S;
  201. q.z = 0.25 * S;
  202. }
  203. return normalize(q);
  204. }
  205. quaternion_look_at :: proc(eye, centre: Vector3, up: Vector3) -> Quaternion {
  206. return quaternion_from_forward_and_up(centre-eye, up);
  207. }
  208. quaternion_nlerp :: proc(a, b: Quaternion, t: Float) -> Quaternion {
  209. c := a + (b-a)*quaternion(t, 0, 0, 0);
  210. return normalize(c);
  211. }
  212. quaternion_slerp :: proc(x, y: Quaternion, t: Float) -> Quaternion {
  213. a, b := x, y;
  214. cos_angle := dot(a, b);
  215. if cos_angle < 0 {
  216. b = -b;
  217. cos_angle = -cos_angle;
  218. }
  219. if cos_angle > 1 - FLOAT_EPSILON {
  220. return a + (b-a)*quaternion(t, 0, 0, 0);
  221. }
  222. angle := math.acos(cos_angle);
  223. sin_angle := math.sin(angle);
  224. factor_a, factor_b: Quaternion;
  225. factor_a = quaternion(math.sin((1-t) * angle) / sin_angle, 0, 0, 0);
  226. factor_b = quaternion(math.sin(t * angle) / sin_angle, 0, 0, 0);
  227. return factor_a * a + factor_b * b;
  228. }
  229. quaternion_from_matrix4 :: proc(m: Matrix4) -> Quaternion {
  230. four_x_squared_minus_1, four_y_squared_minus_1,
  231. four_z_squared_minus_1, four_w_squared_minus_1,
  232. four_biggest_squared_minus_1: Float;
  233. /* xyzw */
  234. /* 0123 */
  235. biggest_index := 3;
  236. biggest_value, mult: Float;
  237. four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
  238. four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
  239. four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
  240. four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
  241. four_biggest_squared_minus_1 = four_w_squared_minus_1;
  242. if four_x_squared_minus_1 > four_biggest_squared_minus_1 {
  243. four_biggest_squared_minus_1 = four_x_squared_minus_1;
  244. biggest_index = 0;
  245. }
  246. if four_y_squared_minus_1 > four_biggest_squared_minus_1 {
  247. four_biggest_squared_minus_1 = four_y_squared_minus_1;
  248. biggest_index = 1;
  249. }
  250. if four_z_squared_minus_1 > four_biggest_squared_minus_1 {
  251. four_biggest_squared_minus_1 = four_z_squared_minus_1;
  252. biggest_index = 2;
  253. }
  254. biggest_value = math.sqrt(four_biggest_squared_minus_1 + 1) * 0.5;
  255. mult = 0.25 / biggest_value;
  256. switch biggest_index {
  257. case 0:
  258. return quaternion(
  259. biggest_value,
  260. (m[0][1] + m[1][0]) * mult,
  261. (m[2][0] + m[0][2]) * mult,
  262. (m[1][2] - m[2][1]) * mult,
  263. );
  264. case 1:
  265. return quaternion(
  266. (m[0][1] + m[1][0]) * mult,
  267. biggest_value,
  268. (m[1][2] + m[2][1]) * mult,
  269. (m[2][0] - m[0][2]) * mult,
  270. );
  271. case 2:
  272. return quaternion(
  273. (m[2][0] + m[0][2]) * mult,
  274. (m[1][2] + m[2][1]) * mult,
  275. biggest_value,
  276. (m[0][1] - m[1][0]) * mult,
  277. );
  278. case 3:
  279. return quaternion(
  280. (m[1][2] - m[2][1]) * mult,
  281. (m[2][0] - m[0][2]) * mult,
  282. (m[0][1] - m[1][0]) * mult,
  283. biggest_value,
  284. );
  285. }
  286. return 0;
  287. }
  288. quaternion_from_matrix3 :: proc(m: Matrix3) -> Quaternion {
  289. four_x_squared_minus_1, four_y_squared_minus_1,
  290. four_z_squared_minus_1, four_w_squared_minus_1,
  291. four_biggest_squared_minus_1: Float;
  292. /* xyzw */
  293. /* 0123 */
  294. biggest_index := 3;
  295. biggest_value, mult: Float;
  296. four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
  297. four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
  298. four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
  299. four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
  300. four_biggest_squared_minus_1 = four_w_squared_minus_1;
  301. if four_x_squared_minus_1 > four_biggest_squared_minus_1 {
  302. four_biggest_squared_minus_1 = four_x_squared_minus_1;
  303. biggest_index = 0;
  304. }
  305. if four_y_squared_minus_1 > four_biggest_squared_minus_1 {
  306. four_biggest_squared_minus_1 = four_y_squared_minus_1;
  307. biggest_index = 1;
  308. }
  309. if four_z_squared_minus_1 > four_biggest_squared_minus_1 {
  310. four_biggest_squared_minus_1 = four_z_squared_minus_1;
  311. biggest_index = 2;
  312. }
  313. biggest_value = math.sqrt(four_biggest_squared_minus_1 + 1) * 0.5;
  314. mult = 0.25 / biggest_value;
  315. switch biggest_index {
  316. case 0:
  317. return quaternion(
  318. biggest_value,
  319. (m[0][1] + m[1][0]) * mult,
  320. (m[2][0] + m[0][2]) * mult,
  321. (m[1][2] - m[2][1]) * mult,
  322. );
  323. case 1:
  324. return quaternion(
  325. (m[0][1] + m[1][0]) * mult,
  326. biggest_value,
  327. (m[1][2] + m[2][1]) * mult,
  328. (m[2][0] - m[0][2]) * mult,
  329. );
  330. case 2:
  331. return quaternion(
  332. (m[2][0] + m[0][2]) * mult,
  333. (m[1][2] + m[2][1]) * mult,
  334. biggest_value,
  335. (m[0][1] - m[1][0]) * mult,
  336. );
  337. case 3:
  338. return quaternion(
  339. (m[1][2] - m[2][1]) * mult,
  340. (m[2][0] - m[0][2]) * mult,
  341. (m[0][1] - m[1][0]) * mult,
  342. biggest_value,
  343. );
  344. }
  345. return 0;
  346. }
  347. quaternion_between_two_vector3 :: proc(from, to: Vector3) -> Quaternion {
  348. x := normalize(from);
  349. y := normalize(to);
  350. cos_theta := dot(x, y);
  351. if abs(cos_theta + 1) < 2*FLOAT_EPSILON {
  352. v := vector3_orthogonal(x);
  353. return quaternion(0, v.x, v.y, v.z);
  354. }
  355. v := cross(x, y);
  356. w := cos_theta + 1;
  357. return Quaternion(normalize(quaternion(w, v.x, v.y, v.z)));
  358. }
  359. matrix2_inverse_transpose :: proc(m: Matrix2) -> Matrix2 {
  360. c: Matrix2;
  361. d := m[0][0]*m[1][1] - m[1][0]*m[0][1];
  362. id := 1.0/d;
  363. c[0][0] = +m[1][1] * id;
  364. c[0][1] = -m[0][1] * id;
  365. c[1][0] = -m[1][0] * id;
  366. c[1][1] = +m[0][0] * id;
  367. return c;
  368. }
  369. matrix2_determinant :: proc(m: Matrix2) -> Float {
  370. return m[0][0]*m[1][1] - m[1][0]*m[0][1];
  371. }
  372. matrix2_inverse :: proc(m: Matrix2) -> Matrix2 {
  373. c: Matrix2;
  374. d := m[0][0]*m[1][1] - m[1][0]*m[0][1];
  375. id := 1.0/d;
  376. c[0][0] = +m[1][1] * id;
  377. c[1][0] = -m[0][1] * id;
  378. c[0][1] = -m[1][0] * id;
  379. c[1][1] = +m[0][0] * id;
  380. return c;
  381. }
  382. matrix2_adjoint :: proc(m: Matrix2) -> Matrix2 {
  383. c: Matrix2;
  384. c[0][0] = +m[1][1];
  385. c[0][1] = -m[1][0];
  386. c[1][0] = -m[0][1];
  387. c[1][1] = +m[0][0];
  388. return c;
  389. }
  390. matrix3_from_quaternion :: proc(q: Quaternion) -> Matrix3 {
  391. xx := q.x * q.x;
  392. xy := q.x * q.y;
  393. xz := q.x * q.z;
  394. xw := q.x * q.w;
  395. yy := q.y * q.y;
  396. yz := q.y * q.z;
  397. yw := q.y * q.w;
  398. zz := q.z * q.z;
  399. zw := q.z * q.w;
  400. m: Matrix3;
  401. m[0][0] = 1 - 2 * (yy + zz);
  402. m[1][0] = 2 * (xy - zw);
  403. m[2][0] = 2 * (xz + yw);
  404. m[0][1] = 2 * (xy + zw);
  405. m[1][1] = 1 - 2 * (xx + zz);
  406. m[2][1] = 2 * (yz - xw);
  407. m[0][2] = 2 * (xz - yw);
  408. m[1][2] = 2 * (yz + xw);
  409. m[2][2] = 1 - 2 * (xx + yy);
  410. return m;
  411. }
  412. matrix3_inverse :: proc(m: Matrix3) -> Matrix3 {
  413. return transpose(matrix3_inverse_transpose(m));
  414. }
  415. matrix3_determinant :: proc(m: Matrix3) -> Float {
  416. a := +m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]);
  417. b := -m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]);
  418. c := +m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
  419. return a + b + c;
  420. }
  421. matrix3_adjoint :: proc(m: Matrix3) -> Matrix3 {
  422. adjoint: Matrix3;
  423. adjoint[0][0] = +(m[1][1] * m[2][2] - m[1][2] * m[2][1]);
  424. adjoint[1][0] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]);
  425. adjoint[2][0] = +(m[0][1] * m[1][2] - m[0][2] * m[1][1]);
  426. adjoint[0][1] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]);
  427. adjoint[1][1] = +(m[0][0] * m[2][2] - m[0][2] * m[2][0]);
  428. adjoint[2][1] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]);
  429. adjoint[0][2] = +(m[1][0] * m[2][1] - m[1][1] * m[2][0]);
  430. adjoint[1][2] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]);
  431. adjoint[2][2] = +(m[0][0] * m[1][1] - m[0][1] * m[1][0]);
  432. return adjoint;
  433. }
  434. matrix3_inverse_transpose :: proc(m: Matrix3) -> Matrix3 {
  435. inverse_transpose: Matrix3;
  436. adjoint := matrix3_adjoint(m);
  437. determinant := matrix3_determinant(m);
  438. inv_determinant := 1.0 / determinant;
  439. for i in 0..<3 {
  440. for j in 0..<3 {
  441. inverse_transpose[i][j] = adjoint[i][j] * inv_determinant;
  442. }
  443. }
  444. return inverse_transpose;
  445. }
  446. matrix3_scale :: proc(s: Vector3) -> Matrix3 {
  447. m: Matrix3;
  448. m[0][0] = s[0];
  449. m[1][1] = s[1];
  450. m[2][2] = s[2];
  451. return m;
  452. }
  453. matrix3_rotate :: proc(angle_radians: Float, v: Vector3) -> Matrix3 {
  454. c := math.cos(angle_radians);
  455. s := math.sin(angle_radians);
  456. a := normalize(v);
  457. t := a * (1-c);
  458. rot: Matrix3 = ---;
  459. rot[0][0] = c + t[0]*a[0];
  460. rot[0][1] = 0 + t[0]*a[1] + s*a[2];
  461. rot[0][2] = 0 + t[0]*a[2] - s*a[1];
  462. rot[1][0] = 0 + t[1]*a[0] - s*a[2];
  463. rot[1][1] = c + t[1]*a[1];
  464. rot[1][2] = 0 + t[1]*a[2] + s*a[0];
  465. rot[2][0] = 0 + t[2]*a[0] + s*a[1];
  466. rot[2][1] = 0 + t[2]*a[1] - s*a[0];
  467. rot[2][2] = c + t[2]*a[2];
  468. return rot;
  469. }
  470. matrix3_look_at :: proc(eye, centre, up: Vector3) -> Matrix3 {
  471. f := normalize(centre - eye);
  472. s := normalize(cross(f, up));
  473. u := cross(s, f);
  474. return Matrix3{
  475. {+s.x, +u.x, -f.x},
  476. {+s.y, +u.y, -f.y},
  477. {+s.z, +u.z, -f.z},
  478. };
  479. }
  480. matrix4_from_quaternion :: proc(q: Quaternion) -> Matrix4 {
  481. m := identity(Matrix4);
  482. xx := q.x * q.x;
  483. xy := q.x * q.y;
  484. xz := q.x * q.z;
  485. xw := q.x * q.w;
  486. yy := q.y * q.y;
  487. yz := q.y * q.z;
  488. yw := q.y * q.w;
  489. zz := q.z * q.z;
  490. zw := q.z * q.w;
  491. m[0][0] = 1 - 2 * (yy + zz);
  492. m[1][0] = 2 * (xy - zw);
  493. m[2][0] = 2 * (xz + yw);
  494. m[0][1] = 2 * (xy + zw);
  495. m[1][1] = 1 - 2 * (xx + zz);
  496. m[2][1] = 2 * (yz - xw);
  497. m[0][2] = 2 * (xz - yw);
  498. m[1][2] = 2 * (yz + xw);
  499. m[2][2] = 1 - 2 * (xx + yy);
  500. return m;
  501. }
  502. matrix4_from_trs :: proc(t: Vector3, r: Quaternion, s: Vector3) -> Matrix4 {
  503. translation := matrix4_translate(t);
  504. rotation := matrix4_from_quaternion(r);
  505. scale := matrix4_scale(s);
  506. return mul(translation, mul(rotation, scale));
  507. }
  508. matrix4_inverse :: proc(m: Matrix4) -> Matrix4 {
  509. return transpose(matrix4_inverse_transpose(m));
  510. }
  511. matrix4_minor :: proc(m: Matrix4, c, r: int) -> Float {
  512. cut_down: Matrix3;
  513. for i in 0..<3 {
  514. col := i < c ? i : i+1;
  515. for j in 0..<3 {
  516. row := j < r ? j : j+1;
  517. cut_down[i][j] = m[col][row];
  518. }
  519. }
  520. return matrix3_determinant(cut_down);
  521. }
  522. matrix4_cofactor :: proc(m: Matrix4, c, r: int) -> Float {
  523. sign, minor: Float;
  524. sign = (c + r) % 2 == 0 ? 1 : -1;
  525. minor = matrix4_minor(m, c, r);
  526. return sign * minor;
  527. }
  528. matrix4_adjoint :: proc(m: Matrix4) -> Matrix4 {
  529. adjoint: Matrix4;
  530. for i in 0..<4 {
  531. for j in 0..<4 {
  532. adjoint[i][j] = matrix4_cofactor(m, i, j);
  533. }
  534. }
  535. return adjoint;
  536. }
  537. matrix4_determinant :: proc(m: Matrix4) -> Float {
  538. adjoint := matrix4_adjoint(m);
  539. determinant: Float = 0;
  540. for i in 0..<4 {
  541. determinant += m[i][0] * adjoint[i][0];
  542. }
  543. return determinant;
  544. }
  545. matrix4_inverse_transpose :: proc(m: Matrix4) -> Matrix4 {
  546. adjoint := matrix4_adjoint(m);
  547. determinant: Float = 0;
  548. for i in 0..<4 {
  549. determinant += m[i][0] * adjoint[i][0];
  550. }
  551. inv_determinant := 1.0 / determinant;
  552. inverse_transpose: Matrix4;
  553. for i in 0..<4 {
  554. for j in 0..<4 {
  555. inverse_transpose[i][j] = adjoint[i][j] * inv_determinant;
  556. }
  557. }
  558. return inverse_transpose;
  559. }
  560. matrix4_translate :: proc(v: Vector3) -> Matrix4 {
  561. m := identity(Matrix4);
  562. m[3][0] = v[0];
  563. m[3][1] = v[1];
  564. m[3][2] = v[2];
  565. return m;
  566. }
  567. matrix4_rotate :: proc(angle_radians: Float, v: Vector3) -> Matrix4 {
  568. c := math.cos(angle_radians);
  569. s := math.sin(angle_radians);
  570. a := normalize(v);
  571. t := a * (1-c);
  572. rot := identity(Matrix4);
  573. rot[0][0] = c + t[0]*a[0];
  574. rot[0][1] = 0 + t[0]*a[1] + s*a[2];
  575. rot[0][2] = 0 + t[0]*a[2] - s*a[1];
  576. rot[0][3] = 0;
  577. rot[1][0] = 0 + t[1]*a[0] - s*a[2];
  578. rot[1][1] = c + t[1]*a[1];
  579. rot[1][2] = 0 + t[1]*a[2] + s*a[0];
  580. rot[1][3] = 0;
  581. rot[2][0] = 0 + t[2]*a[0] + s*a[1];
  582. rot[2][1] = 0 + t[2]*a[1] - s*a[0];
  583. rot[2][2] = c + t[2]*a[2];
  584. rot[2][3] = 0;
  585. return rot;
  586. }
  587. matrix4_scale :: proc(v: Vector3) -> Matrix4 {
  588. m: Matrix4;
  589. m[0][0] = v[0];
  590. m[1][1] = v[1];
  591. m[2][2] = v[2];
  592. m[3][3] = 1;
  593. return m;
  594. }
  595. matrix4_look_at :: proc(eye, centre, up: Vector3) -> Matrix4 {
  596. f := normalize(centre - eye);
  597. s := normalize(cross(f, up));
  598. u := cross(s, f);
  599. return Matrix4{
  600. {+s.x, +u.x, -f.x, 0},
  601. {+s.y, +u.y, -f.y, 0},
  602. {+s.z, +u.z, -f.z, 0},
  603. {-dot(s, eye), -dot(u, eye), +dot(f, eye), 1},
  604. };
  605. }
  606. matrix4_perspective :: proc(fovy, aspect, near, far: Float, flip_z_axis := true) -> (m: Matrix4) {
  607. tan_half_fovy := math.tan(0.5 * fovy);
  608. m[0][0] = 1 / (aspect*tan_half_fovy);
  609. m[1][1] = 1 / (tan_half_fovy);
  610. m[2][2] = +(far + near) / (far - near);
  611. m[2][3] = +1;
  612. m[3][2] = -2*far*near / (far - near);
  613. if flip_z_axis {
  614. m[2] = -m[2];
  615. }
  616. return;
  617. }
  618. matrix_ortho3d :: proc(left, right, bottom, top, near, far: Float, flip_z_axis := true) -> (m: Matrix4) {
  619. m[0][0] = +2 / (right - left);
  620. m[1][1] = +2 / (top - bottom);
  621. m[2][2] = +2 / (far - near);
  622. m[3][0] = -(right + left) / (right - left);
  623. m[3][1] = -(top + bottom) / (top - bottom);
  624. m[3][2] = -(far + near) / (far- near);
  625. m[3][3] = 1;
  626. if flip_z_axis {
  627. m[2] = -m[2];
  628. }
  629. return;
  630. }
  631. matrix4_infinite_perspective :: proc(fovy, aspect, near: Float, flip_z_axis := true) -> (m: Matrix4) {
  632. tan_half_fovy := math.tan(0.5 * fovy);
  633. m[0][0] = 1 / (aspect*tan_half_fovy);
  634. m[1][1] = 1 / (tan_half_fovy);
  635. m[2][2] = +1;
  636. m[2][3] = +1;
  637. m[3][2] = -2*near;
  638. if flip_z_axis {
  639. m[2] = -m[2];
  640. }
  641. return;
  642. }