Files
Odin/core/math/linalg/extended.odin
T

554 lines
12 KiB
Odin

package linalg
import "core:builtin"
import "core:math"
radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = degrees * RAD_PER_DEG;
}
} else {
out = degrees * RAD_PER_DEG;
}
return;
}
degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = radians * DEG_PER_RAD;
}
} else {
out = radians * DEG_PER_RAD;
}
return;
}
min_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = builtin.min(a[i], b[i]);
}
} else {
out = builtin.min(a, b);
}
return;
}
min_single :: proc(a: $T) -> (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..<N {
out = builtin.min(out, a[i]);
}
}
} else {
out = a;
}
return;
}
min_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
return min_double(a, min_double(b, c));
}
min :: proc{min_single, min_double, min_triple};
max_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = builtin.max(a[i], b[i]);
}
} else {
out = builtin.max(a, b);
}
return;
}
max_single :: proc(a: $T) -> (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[3]);
}else {
out = builtin.max(a[0], a[1]);
for i in 2..<N {
out = builtin.max(out, a[i]);
}
}
} else {
out = a;
}
return;
}
max_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
return max_double(a, max_double(b, c));
}
max :: proc{max_single, max_double, max_triple};
abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = builtin.abs(a[i]);
}
} else {
out = builtin.abs(a);
}
return;
}
sign :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = #force_inline math.sign(a[i]);
}
} else {
out = #force_inline math.sign(a);
}
return;
}
clamp :: proc(x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = builtin.clamp(x[i], a[i], b[i]);
}
} else {
out = builtin.clamp(x, a, b);
}
return;
}
saturate :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
return clamp(x, 0.0, 1.0);
}
lerp :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = a[i]*(1-t[i]) + b[i]*t[i];
}
} else {
out = a * (1.0 - t) + b * t;
}
return;
}
mix :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = a[i]*(1-t[i]) + b[i]*t[i];
}
} else {
out = a * (1.0 - t) + b * t;
}
return;
}
unlerp :: proc(a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
return (x - a) / (b - a);
}
step :: proc(e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = x[i] < e[i] ? 0.0 : 1.0;
}
} else {
out = x < e ? 0.0 : 1.0;
}
return;
}
smoothstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
t := saturate(unlerp(e0, e1, x));
return t * t * (3.0 - 2.0 * t);
}
smootherstep :: proc(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);
}
sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.sqrt(x[i]);
}
} else {
out = math.sqrt(x);
}
return;
}
inverse_sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = 1.0/math.sqrt(x[i]);
}
} else {
out = 1.0/math.sqrt(x);
}
return;
}
cos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.cos(x[i]);
}
} else {
out = math.cos(x);
}
return;
}
sin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.sin(x[i]);
}
} else {
out = math.sin(x);
}
return;
}
tan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.tan(x[i]);
}
} else {
out = math.tan(x);
}
return;
}
acos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.acos(x[i]);
}
} else {
out = math.acos(x);
}
return;
}
asin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.asin(x[i]);
}
} else {
out = math.asin(x);
}
return;
}
atan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.atan(x[i]);
}
} else {
out = math.atan(x);
}
return;
}
atan2 :: proc(y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.atan2(y[i], x[i]);
}
} else {
out = math.atan2(y, x);
}
return;
}
ln :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.ln(x[i]);
}
} else {
out = math.ln(x);
}
return;
}
log2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = INVLN2 * math.ln(x[i]);
}
} else {
out = INVLN2 * math.ln(x);
}
return;
}
log10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = INVLN10 * math.ln(x[i]);
}
} else {
out = INVLN10 * math.ln(x);
}
return;
}
log :: proc(x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i]);
}
} else {
out = INVLN10 * math.ln(x) / math.ln(cast(ELEM_TYPE(T))b);
}
return;
}
exp :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.exp(x[i]);
}
} else {
out = math.exp(x);
}
return;
}
exp2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.exp(LN2 * x[i]);
}
} else {
out = math.exp(LN2 * x);
}
return;
}
exp10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.exp(LN10 * x[i]);
}
} else {
out = math.exp(LN10 * x);
}
return;
}
pow :: proc(x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = math.pow(x[i], e[i]);
}
} else {
out = math.pow(x, e);
}
return;
}
ceil :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = #force_inline math.ceil(x[i]);
}
} else {
out = #force_inline math.ceil(x);
}
return;
}
floor :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = #force_inline math.floor(x[i]);
}
} else {
out = #force_inline math.floor(x);
}
return;
}
round :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
out[i] = #force_inline math.round(x[i]);
}
} else {
out = #force_inline math.round(x);
}
return;
}
fract :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
f := #force_inline floor(x);
return x - f;
}
mod :: proc(x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
f := #force_inline floor(x / m);
return x - f * m;
}
face_forward :: proc(N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
return dot(N_ref, I) < 0 ? N : -N;
}
distance :: proc(p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) {
return length(p1 - p0);
}
reflect :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
b := n * (2 * dot(n, i));
return i - b;
}
refract :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
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));
}
is_nan_single :: proc(x: $T) -> bool where IS_FLOAT(T) {
return #force_inline math.is_nan(x);
}
is_nan_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
for i in 0..<N {
out[i] = #force_inline is_nan(x[i]);
}
return;
}
is_inf_single :: proc(x: $T) -> bool where IS_FLOAT(T) {
return #force_inline math.is_inf(x);
}
is_inf_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
for i in 0..<N {
out[i] = #force_inline is_inf(x[i]);
}
return;
}
classify_single :: proc(x: $T) -> math.Float_Class where IS_FLOAT(T) {
return #force_inline math.classify(x);
}
classify_array :: proc(x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
for i in 0..<N {
out[i] = #force_inline classify_single(x[i]);
}
return;
}
is_nan :: proc{is_nan_single, is_nan_array};
is_inf :: proc{is_inf_single, is_inf_array};
classify :: proc{classify_single, classify_array};
less_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y; }
less_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y; }
greater_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y; }
greater_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y; }
equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y; }
not_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y; }
less_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
out[i] = x[i] < y[i];
}
return;
}
less_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
out[i] = x[i] <= y[i];
}
return;
}
greater_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
out[i] = x[i] > y[i];
}
return;
}
greater_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
out[i] = x[i] >= y[i];
}
return;
}
equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
out[i] = x[i] == y[i];
}
return;
}
not_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
out[i] = x[i] != y[i];
}
return;
}
less_than :: proc{less_than_single, less_than_array};
less_than_equal :: proc{less_than_equal_single, less_than_equal_array};
greater_than :: proc{greater_than_single, greater_than_array};
greater_than_equal :: proc{greater_than_equal_single, greater_than_equal_array};
equal :: proc{equal_single, equal_array};
not_equal :: proc{not_equal_single, not_equal_array};
any :: proc(x: $A/[$N]bool) -> (out: bool) {
for e in x {
if x {
return true;
}
}
return false;
}
all :: proc(x: $A/[$N]bool) -> (out: bool) {
for e in x {
if !e {
return false;
}
}
return true;
}
not :: proc(x: $A/[$N]bool) -> (out: A) {
for e, i in x {
out[i] = !e;
}
return;
}