package linalg import "core:builtin" import "core:math" @(require_results) to_radians :: proc "contextless" (degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { N :: len(T) when N == 1 { out = a[0] } else when N == 2 { out = builtin.min(a[0], a[1]) } else { out = builtin.min(a[0], a[1]) for i in 2.. T where IS_NUMERIC(ELEM_TYPE(T)) { return min_double(a, min_double(b, c)) } min :: proc{min_single, min_double, min_triple} @(require_results) max_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { N :: len(T) when N == 1 { out = a[0] } else when N == 2 { out = builtin.max(a[0], a[1]) } else when N == 3 { out = builtin.max(a[0], a[1], a[2]) }else { out = builtin.max(a[0], a[1]) for i in 2.. T where IS_NUMERIC(ELEM_TYPE(T)) { return max_double(a, max_double(b, c)) } max :: proc{max_single, max_double, max_triple} @(require_results) abs :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. T where IS_FLOAT(ELEM_TYPE(T)) { return clamp(x, 0.0, 1.0) } @(require_results) lerp :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. T where IS_FLOAT(ELEM_TYPE(T)) { return (x - a) / (b - a) } @(require_results) step :: proc "contextless" (e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. T where IS_FLOAT(ELEM_TYPE(T)) { t := saturate(unlerp(e0, e1, x)) return t * t * (3.0 - 2.0 * t) } @(require_results) smootherstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { t := saturate(unlerp(e0, e1, x)) return t * t * t * (t * (6*t - 15) + 10) } @(require_results) sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. (out: T) where IS_FLOAT(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. T where IS_FLOAT(ELEM_TYPE(T)) { f := #force_inline floor(x) return x - f } @(require_results) mod :: proc "contextless" (x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { f := #force_inline floor(x / m) return x - f * m } @(require_results) face_forward :: proc "contextless" (N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { return dot(N_ref, I) < 0 ? N : -N } @(require_results) distance :: proc "contextless" (p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) { return length(p1 - p0) } @(require_results) reflect :: proc "contextless" (I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { b := N * (2 * dot(N, I)) return I - b } @(require_results) refract :: proc "contextless" (I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) { dv := dot(Normal, I) k := 1 - eta*eta * (1 - dv*dv) a := I * eta b := Normal * (eta*dv+math.sqrt(k)) return (a - b) * E(int(k >= 0)) } @(require_results) is_nan_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) { return #force_inline math.is_nan(x) } @(require_results) is_nan_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) { for i in 0.. bool where IS_FLOAT(T) { return #force_inline math.is_inf(x) } @(require_results) is_inf_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) { for i in 0.. math.Float_Class where IS_FLOAT(T) { return #force_inline math.classify(x) } @(require_results) classify_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) { for i in 0.. (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y } @(require_results) less_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y } @(require_results) greater_than_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y } @(require_results) greater_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y } @(require_results) equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y } @(require_results) not_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y } @(require_results) less_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. y[i] } return } @(require_results) greater_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0..= y[i] } return } @(require_results) equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: bool) { for e in x { if e { return true } } return false } @(require_results) all :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) { for e in x { if !e { return false } } return true } @(require_results) not :: proc "contextless" (x: $A/[$N]bool) -> (out: A) { for e, i in x { out[i] = !e } return }