linalg.odin 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. package linalg
  2. import "core:math"
  3. import "intrinsics"
  4. // Generic
  5. dot_vector :: proc(a, b: $T/[$N]$E) -> (c: E) {
  6. for i in 0..<N {
  7. c += a[i] * b[i];
  8. }
  9. return;
  10. }
  11. dot_quaternion128 :: proc(a, b: $T/quaternion128) -> (c: f32) {
  12. return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
  13. }
  14. dot_quaternion256 :: proc(a, b: $T/quaternion256) -> (c: f64) {
  15. return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
  16. }
  17. dot :: proc{dot_vector, dot_quaternion128, dot_quaternion256};
  18. cross2 :: proc(a, b: $T/[2]$E) -> E {
  19. return a[0]*b[1] - b[0]*a[1];
  20. }
  21. cross3 :: proc(a, b: $T/[3]$E) -> (c: T) {
  22. c[0] = +(a[1]*b[2] - b[1]*a[2]);
  23. c[1] = -(a[2]*b[3] - b[2]*a[3]);
  24. c[2] = +(a[3]*b[1] - b[3]*a[1]);
  25. return;
  26. }
  27. cross :: proc{cross2, cross3};
  28. normalize_vector :: proc(v: $T/[$N]$E) -> T {
  29. return v / length(v);
  30. }
  31. normalize_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
  32. return q/abs(q);
  33. }
  34. normalize_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
  35. return q/abs(q);
  36. }
  37. normalize :: proc{normalize_vector, normalize_quaternion128, normalize_quaternion256};
  38. normalize0_vector :: proc(v: $T/[$N]$E) -> T {
  39. m := length(v);
  40. return m == 0 ? 0 : v/m;
  41. }
  42. normalize0_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
  43. m := abs(q);
  44. return m == 0 ? 0 : q/m;
  45. }
  46. normalize0_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
  47. m := abs(q);
  48. return m == 0 ? 0 : q/m;
  49. }
  50. normalize0 :: proc{normalize0_vector, normalize0_quaternion128, normalize0_quaternion256};
  51. length :: proc(v: $T/[$N]$E) -> E {
  52. return math.sqrt(dot(v, v));
  53. }
  54. identity :: proc($T: typeid/[$N][N]$E) -> (m: T) {
  55. for i in 0..<N do m[i][i] = E(1);
  56. return m;
  57. }
  58. transpose :: proc(a: $T/[$N][$M]$E) -> (m: [M][N]E) {
  59. for j in 0..<M {
  60. for i in 0..<N {
  61. m[j][i] = a[i][j];
  62. }
  63. }
  64. return;
  65. }
  66. mul_matrix :: proc(a, b: $M/[$N][N]$E) -> (c: M)
  67. where !intrinsics.type_is_array(E),
  68. intrinsics.type_is_numeric(E) {
  69. for i in 0..<N {
  70. for k in 0..<N {
  71. for j in 0..<N {
  72. c[i][k] += a[i][j] * b[j][k];
  73. }
  74. }
  75. }
  76. return;
  77. }
  78. mul_matrix_differ :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: [I][K]E)
  79. where !intrinsics.type_is_array(E),
  80. intrinsics.type_is_numeric(E),
  81. I != J {
  82. for i in 0..<I {
  83. for k in 0..<K {
  84. for j in 0..<J {
  85. c[i][k] += a[i][j] * b[j][k];
  86. }
  87. }
  88. }
  89. return;
  90. }
  91. mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
  92. where !intrinsics.type_is_array(E),
  93. intrinsics.type_is_numeric(E) {
  94. for i in 0..<I {
  95. for j in 0..<J {
  96. c[i] += a[i][j] * b[i];
  97. }
  98. }
  99. return;
  100. }
  101. mul_quaternion128_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
  102. Raw_Quaternion :: struct {xyz: [3]f32, r: f32};
  103. q := transmute(Raw_Quaternion)q;
  104. v := transmute([3]f32)v;
  105. t := cross(2*q.xyz, v);
  106. return V(v + q.r*t + cross(q.xyz, t));
  107. }
  108. mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
  109. Raw_Quaternion :: struct {xyz: [3]f64, r: f64};
  110. q := transmute(Raw_Quaternion)q;
  111. v := transmute([3]f64)v;
  112. t := cross(2*q.xyz, v);
  113. return V(v + q.r*t + cross(q.xyz, t));
  114. }
  115. mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3};
  116. mul :: proc{
  117. mul_matrix,
  118. mul_matrix_differ,
  119. mul_matrix_vector,
  120. mul_quaternion128_vector3,
  121. mul_quaternion256_vector3,
  122. };
  123. // Specific
  124. Float :: f32;
  125. Vector2 :: distinct [2]Float;
  126. Vector3 :: distinct [3]Float;
  127. Vector4 :: distinct [4]Float;
  128. Matrix2x1 :: distinct [2][1]Float;
  129. Matrix2x2 :: distinct [2][2]Float;
  130. Matrix2x3 :: distinct [2][3]Float;
  131. Matrix2x4 :: distinct [2][4]Float;
  132. Matrix3x1 :: distinct [3][1]Float;
  133. Matrix3x2 :: distinct [3][2]Float;
  134. Matrix3x3 :: distinct [3][3]Float;
  135. Matrix3x4 :: distinct [3][4]Float;
  136. Matrix4x1 :: distinct [4][1]Float;
  137. Matrix4x2 :: distinct [4][2]Float;
  138. Matrix4x3 :: distinct [4][3]Float;
  139. Matrix4x4 :: distinct [4][4]Float;
  140. Matrix2 :: Matrix2x2;
  141. Matrix3 :: Matrix3x3;
  142. Matrix4 :: Matrix4x4;
  143. Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256);
  144. translate_matrix4 :: proc(v: Vector3) -> Matrix4 {
  145. m := identity(Matrix4);
  146. m[3][0] = v[0];
  147. m[3][1] = v[1];
  148. m[3][2] = v[2];
  149. return m;
  150. }
  151. rotate_matrix4 :: proc(v: Vector3, angle_radians: Float) -> Matrix4 {
  152. c := math.cos(angle_radians);
  153. s := math.sin(angle_radians);
  154. a := normalize(v);
  155. t := a * (1-c);
  156. rot := identity(Matrix4);
  157. rot[0][0] = c + t[0]*a[0];
  158. rot[0][1] = 0 + t[0]*a[1] + s*a[2];
  159. rot[0][2] = 0 + t[0]*a[2] - s*a[1];
  160. rot[0][3] = 0;
  161. rot[1][0] = 0 + t[1]*a[0] - s*a[2];
  162. rot[1][1] = c + t[1]*a[1];
  163. rot[1][2] = 0 + t[1]*a[2] + s*a[0];
  164. rot[1][3] = 0;
  165. rot[2][0] = 0 + t[2]*a[0] + s*a[1];
  166. rot[2][1] = 0 + t[2]*a[1] - s*a[0];
  167. rot[2][2] = c + t[2]*a[2];
  168. rot[2][3] = 0;
  169. return rot;
  170. }
  171. scale_matrix4 :: proc(m: Matrix4, v: Vector3) -> Matrix4 {
  172. mm := m;
  173. mm[0][0] *= v[0];
  174. mm[1][1] *= v[1];
  175. mm[2][2] *= v[2];
  176. return mm;
  177. }
  178. look_at :: proc(eye, centre, up: Vector3) -> Matrix4 {
  179. f := normalize(centre - eye);
  180. s := normalize(cross(f, up));
  181. u := cross(s, f);
  182. return Matrix4{
  183. {+s.x, +u.x, -f.x, 0},
  184. {+s.y, +u.y, -f.y, 0},
  185. {+s.z, +u.z, -f.z, 0},
  186. {-dot(s, eye), -dot(u, eye), +dot(f, eye), 1},
  187. };
  188. }
  189. perspective :: proc(fovy, aspect, near, far: Float) -> (m: Matrix4) {
  190. tan_half_fovy := math.tan(0.5 * fovy);
  191. m[0][0] = 1 / (aspect*tan_half_fovy);
  192. m[1][1] = 1 / (tan_half_fovy);
  193. m[2][2] = -(far + near) / (far - near);
  194. m[2][3] = -1;
  195. m[3][2] = -2*far*near / (far - near);
  196. return;
  197. }
  198. ortho3d :: proc(left, right, bottom, top, near, far: Float) -> (m: Matrix4) {
  199. m[0][0] = +2 / (right - left);
  200. m[1][1] = +2 / (top - bottom);
  201. m[2][2] = -2 / (far - near);
  202. m[3][0] = -(right + left) / (right - left);
  203. m[3][1] = -(top + bottom) / (top - bottom);
  204. m[3][2] = -(far + near) / (far- near);
  205. m[3][3] = 1;
  206. return;
  207. }
  208. axis_angle :: proc(axis: Vector3, angle_radians: Float) -> Quaternion {
  209. t := angle_radians*0.5;
  210. w := math.cos(t);
  211. v := normalize(axis) * math.sin(t);
  212. return quaternion(w, v.x, v.y, v.z);
  213. }
  214. angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion {
  215. t := angle_radians*0.5;
  216. w := math.cos(t);
  217. v := normalize(axis) * math.sin(t);
  218. return quaternion(w, v.x, v.y, v.z);
  219. }
  220. euler_angles :: proc(pitch, yaw, roll: Float) -> Quaternion {
  221. p := axis_angle({1, 0, 0}, pitch);
  222. y := axis_angle({0, 1, 0}, yaw);
  223. r := axis_angle({0, 0, 1}, roll);
  224. return (y * p) * r;
  225. }