package linalg import "core:math" import "intrinsics" // Generic @private IS_NUMERIC :: intrinsics.type_is_numeric; @private IS_QUATERNION :: intrinsics.type_is_quaternion; @private IS_ARRAY :: intrinsics.type_is_array; vector_dot :: proc(a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) { for i in 0.. (c: f32) { return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z; } quaternion256_dot :: proc(a, b: $T/quaternion256) -> (c: f64) { return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z; } dot :: proc{vector_dot, quaternion128_dot, quaternion256_dot}; quaternion_inverse :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0); } vector_cross2 :: proc(a, b: $T/[2]$E) -> E where IS_NUMERIC(E) { return a[0]*b[1] - b[0]*a[1]; } vector_cross3 :: proc(a, b: $T/[3]$E) -> (c: T) where IS_NUMERIC(E) { c[0] = a[1]*b[2] - b[1]*a[2]; c[1] = a[2]*b[0] - b[2]*a[0]; c[2] = a[0]*b[1] - b[0]*a[1]; return; } vector_cross :: proc{vector_cross2, vector_cross3}; cross :: vector_cross; vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) { return v / length(v); } quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { return q/abs(q); } normalize :: proc{vector_normalize, quaternion_normalize}; vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) { m := length(v); return m == 0 ? 0 : v/m; } quaternion_normalize0 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { m := abs(q); return m == 0 ? 0 : q/m; } normalize0 :: proc{vector_normalize0, quaternion_normalize0}; vector_length :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) { return math.sqrt(dot(v, v)); } vector_length2 :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) { return dot(v, v); } quaternion_length :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { return abs(q); } quaternion_length2 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { return dot(q, q); } length :: proc{vector_length, quaternion_length}; length2 :: proc{vector_length2, quaternion_length2}; vector_lerp :: proc(x, y, t: $V/[$N]$E) -> V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { s: V; for i in 0.. V where IS_NUMERIC(E) { return length(p1 - p0); } vector_reflect :: proc(i, n: $V/[$N]$E) -> V where IS_NUMERIC(E) { b := n * (2 * dot(n, i)); return i - b; } vector_refract :: proc(i, n: $V/[$N]$E, eta: E) -> V where IS_NUMERIC(E) { dv := dot(n, i); k := 1 - eta*eta - (1 - dv*dv); a := i * eta; b := n * eta*dv*math.sqrt(k); return (a - b) * E(int(k >= 0)); } identity :: proc($T: typeid/[$N][N]$E) -> (m: T) { for i in 0.. (tr: E) { for i in 0.. (m: T) { for j in 0.. (c: M) where !IS_ARRAY(E), IS_NUMERIC(E) { for i in 0.. (c: [K][I]E) where !IS_ARRAY(E), IS_NUMERIC(E), I != K { for k in 0.. (c: B) where !IS_ARRAY(E), IS_NUMERIC(E) { for i in 0.. V { Raw_Quaternion :: struct {xyz: [3]f32, r: f32}; q := transmute(Raw_Quaternion)q; v := transmute([3]f32)v; t := cross(2*q.xyz, v); return V(v + q.r*t + cross(q.xyz, t)); } quaternion256_mul_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V { Raw_Quaternion :: struct {xyz: [3]f64, r: f64}; q := transmute(Raw_Quaternion)q; v := transmute([3]f64)v; t := cross(2*q.xyz, v); return V(v + q.r*t + cross(q.xyz, t)); } quaternion_mul_vector3 :: proc{quaternion128_mul_vector3, quaternion256_mul_vector3}; mul :: proc{ matrix_mul, matrix_mul_differ, matrix_mul_vector, quaternion128_mul_vector3, quaternion256_mul_vector3, }; vector_to_ptr :: proc(v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E) { return &v[0]; } matrix_to_ptr :: proc(m: ^$A/[$I][$J]$E) -> ^E where IS_NUMERIC(E) { return &m[0][0]; }