From 7f444c14e1d8c2cf3ba8c2b4c2092e35cb62d375 Mon Sep 17 00:00:00 2001 From: jesse Date: Tue, 20 May 2025 20:11:01 -0700 Subject: [PATCH] Added vector operations --- math/vec.jai | 204 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 198 insertions(+), 6 deletions(-) diff --git a/math/vec.jai b/math/vec.jai index 75b7f98..5618614 100644 --- a/math/vec.jai +++ b/math/vec.jai @@ -119,6 +119,182 @@ operator / :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc { return res; } +operator + :: inline (l: Vec, r: $R) -> Vec(l.N, l.T) #no_abc #symmetric +#modify { return is_type_scalar(R), "type is not integer or float"; } { + res: Vec(l.N, l.T) = ---; + for l res[it_index] = it + r; + return res; +} + +operator - :: inline (l: Vec, r: $R) -> Vec(l.N, l.T) #no_abc +#modify { return is_type_scalar(R), "type is not integer or float"; } { + res: Vec(l.N, l.T) = ---; + for l res[it_index] = it - r; + return res; +} +operator - :: inline (l: $R, r: Vec) -> Vec(l.N, l.T) #no_abc +#modify { return is_type_scalar(R), "type is not integer or float"; } { + res: Vec(l.N, l.T) = ---; + for l res[it_index] = r - it; + return res; +} + +operator * :: inline (l: Vec, r: $R) -> Vec(l.N, l.T) #no_abc #symmetric +#modify { return is_type_scalar(R), "type is not integer or float"; } { + res: Vec(l.N, l.T) = ---; + for l res[it_index] = it*r; + return res; +} + +operator / :: inline (l: Vec, r: $R) -> Vec(l.N, l.T) #no_abc +#modify { return is_type_scalar(R), "type is not integer or float"; } { + res: Vec(l.N, l.T) = ---; + for l res[it_index] = it/r; + return res; +} + +operator == :: inline (l: Vec, r: Vec(l.N, l.T)) -> bool #no_abc { + for l if it != r[it_index] return false; + return true; +} + +min :: (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc { + res: Vec(l.N, l.T) = ---; + n := l.N - 1; + while n >= 0 { + if l[n] < r[n] + res[n] = l[n]; + else + res[n] = r[n]; + n -= 1; + } + return res; +} + +max :: (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc { + res: Vec(l.N, l.T) = ---; + n := l.N - 1; + while n >= 0 { + if l[n] > r[n] + res[n] = l[n]; + else + res[n] = r[n]; + n -= 1; + } + return res; +} + +ceil :: (l: Vec, x: l.T) -> Vec(l.N, l.T) #no_abc { + r: Vec(l.N, l.T) = ---; + n := l.N - 1; + while n >= 0 { + if x < l[n] + r[n] = x; + else + r[n] = l[n]; + n -= 1; + } + return r; +} + +floor :: (l: Vec, x: l.T) -> Vec(l.N, l.T) #no_abc { + r: Vec(l.N, l.T) = ---; + n := l.N - 1; + while n >= 0 { + if x > l[n] + r[n] = x; + else + r[n] = l[n]; + n -= 1; + } + return r; +} + +clamp :: (v: Vec, low: v.T, high: v.T) -> Vec(v.N, v.T) #no_abc { + r: Vec(v.N, v.T) = ---; + n := v.N - 1; + while n >= 0 { + if v[n] < low + r[n] = low; + else if v[n] > high + r[n] = high; + else + r[n] = v[n]; + n -= 1; + } + return r; +} + +dot :: (a: Vec, b: Vec(a.N, a.T)) -> a.T #no_abc { + sum: a.T; + n := a.N - 1; + while n >= 0 { + sum += a[n]*b[n]; + n -= 1; + } + return sum; +} + +length_squared :: (v: Vec) -> float #no_abc { + return dot(v, v); +} + +length :: (v: Vec) -> float #no_abc { + return math.sqrt(dot(v, v)); +} + +abs :: (v: Vec) -> Vec(v.N, v.T) #no_abc { + r: Vec(v.N, v.T) = ---; + n := v.N - 1; + while n >= 0 { + if v[n] < 0 + r[n] = -v[n]; + else + r[n] = v[n]; + n -= 1; + } + return r; +} + +norm :: normalize; +normalize :: (v: Vec) -> Vec(v.N, v.T) #no_abc { + return v/length(v); +} + +lerp :: (a: Vec, b: Vec(a.N, a.T), t: float) -> Vec(a.N, a.T) #no_abc { + r: Vec(a.N, a.T) = ---; + n := a.N - 1; + while n >= 0 { + r[n] = a[n] + t*(b[n] - a[n]); + n -= 1; + } + return r; +} + +// Note(Jesse): I don't think this is needed for bigger vectors +reflect :: (v: Vec3, p: Vec3) -> Vec3 #no_abc { + projection := p*dot(v, p)/length_squared(p); + return 2*projection - v; +} +reflect :: (v: Vec2, p: Vec2) -> Vec2 #no_abc { + projection := p*dot(v, p)/length_squared(p); + return 2*projection - v; +} + +round :: (v: Vec($N, $T)) -> Vec(N, T) #no_abc +#modify { return is_type_float(T), "Used non-float vector on round"; } { + r: Vec(N, T) = ---; + n := N - 1; + while n >= 0 { + if v[n] < 0 + r[n] = (v[n] - 0.5).(int).(float); + else + r[n] = (v[n] + 0.5).(int).(float); + n -= 1; + } + return r; +} + // Concrete vector types (the usual cases) Vec2 :: Vec(2, float); @@ -127,37 +303,37 @@ Vec4 :: Vec(4, float); Quat :: Vec4; v2f :: (x: $T = 0, y: T = 0) -> Vec2 -#modify { return T.(*Type_Info).type == .FLOAT, "use v2i for integer arguments"; } +#modify { return is_type_float(T), "use v2i for integer arguments"; } #expand { return .{ x = x, y = y }; } v2i :: (x: $T = 0, y: T = 0) -> Vec(2, T) -#modify { return T.(*Type_Info).type == .INTEGER, "use v2f for float arguments"; } +#modify { return is_type_integer(T), "use v2f for float arguments"; } #expand { return .{ x = x, y = y }; } v3f :: (x: $T = 0, y: T = 0, z: T = 0) -> Vec3 -#modify { return T.(*Type_Info).type == .FLOAT, "use v3i for integer arguments"; } +#modify { return is_type_float(T), "use v3i for integer arguments"; } #expand { return .{ x = x, y = y, z = z }; } v3i :: (x: $T = 0, y: T = 0, z: T = 0) -> Vec(3, T) -#modify { return T.(*Type_Info).type == .INTEGER, "use v3f for float arguments"; } +#modify { return is_type_integer(T), "use v3f for float arguments"; } #expand { return .{ x = x, y = y, z = z }; } v4f :: (x: $T = 0, y: T = 0, z: T = 0, w: T = 0) -> Vec4 -#modify { return T.(*Type_Info).type == .FLOAT, "use v4i for integer arguments"; } +#modify { return is_type_float(T), "use v4i for integer arguments"; } #expand { return .{ x = x, y = y, z = z, w = w }; } v4i :: (x: $T = 0, y: T = 0, z: T = 0, w: T = 0) -> Vec(4, T) -#modify { return T.(*Type_Info).type == .INTEGER, "use v4f for float arguments"; } +#modify { return is_type_integer(T), "use v4f for float arguments"; } #expand { return .{ x = x, y = y, z = z, w = w }; } @@ -165,3 +341,19 @@ v4i :: (x: $T = 0, y: T = 0, z: T = 0, w: T = 0) -> Vec(4, T) quat :: (x: float = 0, y: float = 0, z: float = 0, w: float = 0) -> Quat #expand { return .{ x = x, y = y, z = z, w = w }; } + +#scope_file + +math :: #import "Math"; + +is_type_integer :: (t: Type) -> bool { + return t.(*Type_Info).type == .INTEGER; +} + +is_type_float :: (t: Type) -> bool { + return t.(*Type_Info).type == .FLOAT; +} + +is_type_scalar :: (t: Type) -> bool { + return is_type_integer(t) || is_type_float(t); +}