forked from vv/efemra
1
0
Fork 0
efemra/src/math/vec.zig

235 lines
6.9 KiB
Zig

const std = @import("std");
const assert = std.debug.assert;
pub const Vec2f = Vec(2, f32);
pub const Vec3f = Vec(3, f32);
pub const Vec4f = Vec(4, f32);
pub const Vec2i = Vec(2, i32);
pub const Vec3i = Vec(3, i32);
pub const Vec4i = Vec(4, i32);
pub const Vec2u = Vec(2, u32);
pub const Vec3u = Vec(3, u32);
pub const Vec4u = Vec(4, u32);
pub const Vec2b = BoolVec(2);
pub const Vec3b = BoolVec(3);
pub const Vec4b = BoolVec(4);
pub fn BoolVec(comptime nelem: comptime_int) type {
assert(nelem > 1);
assert(nelem <= 4);
return packed struct {
const Self = @This();
x: bool = false,
y: bool = false,
z: if (nelem > 2) bool else void = if (nelem > 2) false else {},
w: if (nelem > 3) bool else void = if (nelem > 3) false else {},
pub inline fn all2(self: Self) bool {
return self.x and self.y;
}
// 3-element operations
pub usingnamespace if (nelem >= 3) struct {
pub inline fn all3(self: Self) bool {
return self.all2() and if (nelem > 2) self.z else true;
}
} else struct {};
pub usingnamespace if (nelem >= 4) struct {
pub inline fn all4(self: Self) bool {
return self.all3() and if (nelem > 3) self.w else true;
}
} else struct {};
};
}
pub fn Vec(comptime nelem: comptime_int, comptime T: type) type {
assert(nelem > 1);
assert(nelem <= 4);
return packed struct {
const Self = @This();
pub const nelem = nelem;
pub const T = T;
const Vecnb = BoolVec(Self.nelem);
x: T = 0,
y: T = 0,
z: if (nelem > 2) T else void = if (nelem > 2) 0 else {},
w: if (nelem > 3) T else void = if (nelem > 3) 0 else {},
pub inline fn s(a: T) Self {
return Self{
.x = a,
.y = a,
.z = if (nelem > 2) a else {},
.w = if (nelem > 3) a else {},
};
}
pub inline fn add(lhs: Self, rhs: Self) Self {
return Self{
.x = lhs.x + rhs.x,
.y = lhs.y + rhs.y,
.z = if (nelem > 2) lhs.z + rhs.z else {},
.w = if (nelem > 3) lhs.w + rhs.w else {},
};
}
pub inline fn sub(lhs: Self, rhs: Self) Self {
return Self{
.x = lhs.x - rhs.x,
.y = lhs.y - rhs.y,
.z = if (nelem > 2) lhs.z - rhs.z else {},
.w = if (nelem > 3) lhs.w - rhs.w else {},
};
}
pub inline fn mul(lhs: Self, rhs: Self) Self {
return Self{
.x = lhs.x * rhs.x,
.y = lhs.y * rhs.y,
.z = if (nelem > 2) lhs.z * rhs.z else {},
.w = if (nelem > 3) lhs.w * rhs.w else {},
};
}
pub inline fn mulvs(lhs: Self, rhs: T) Self {
return Self{
.x = lhs.x * rhs,
.y = lhs.y * rhs,
.z = if (nelem > 2) lhs.z * rhs else {},
.w = if (nelem > 3) lhs.w * rhs else {},
};
}
pub inline fn divvs(lhs: Self, rhs: T) Self {
return lhs.mulvs(1 / rhs);
}
pub inline fn min(a: Self, b: Self) Self {
return Self{
.x = @minimum(a.x, b.x),
.y = @minimum(a.y, b.y),
.z = if (nelem > 2) @minimum(a.z, b.z) else {},
.w = if (nelem > 3) @minimum(a.w, b.w) else {},
};
}
pub inline fn max(a: Self, b: Self) Self {
return Self{
.x = @maximum(a.x, b.x),
.y = @maximum(a.y, b.y),
.z = if (nelem > 2) @maximum(a.z, b.z) else {},
.w = if (nelem > 3) @maximum(a.w, b.w) else {},
};
}
pub inline fn sum(self: Self) T {
return self.x + self.y + if (nelem > 2) self.z else 0 + if (nelem > 3) self.w else 0;
}
pub inline fn dot(a: Self, b: Self) T {
return a.mul(b).sum();
}
pub inline fn length(self: Self) T {
return @sqrt(@maximum(std.math.epsilon(T), self.dot(self)));
}
pub inline fn normalize(self: Self) Self {
return self.divvs(self.length());
}
pub inline fn lteq(lhs: Self, rhs: Self) Vecnb {
return Vecnb{
.x = lhs.x <= rhs.x,
.y = lhs.y <= rhs.y,
.z = if (nelem > 2) lhs.z <= rhs.z else {},
.w = if (nelem > 3) lhs.w <= rhs.w else {},
};
}
pub inline fn gteq(lhs: Self, rhs: Self) Vecnb {
return Vecnb{
.x = lhs.x >= rhs.x,
.y = lhs.y >= rhs.y,
.z = if (nelem > 2) lhs.z >= rhs.z else {},
.w = if (nelem > 3) lhs.w >= rhs.w else {},
};
}
// 3-element operations
pub usingnamespace if (nelem >= 3) struct {
pub inline fn sum3(self: Self) T {
return self.x + self.y + self.z;
}
pub inline fn dot3(a: Self, b: Self) T {
return a.mul(b).sum3();
}
pub inline fn xzy(self: Self) Self {
return Self{
.x = self.x,
.y = self.z,
.z = self.y,
.w = if (nelem > 3) 0 else {},
};
}
pub inline fn zxy(self: Self) Self {
return Self{
.x = self.z,
.y = self.x,
.z = self.y,
.w = if (nelem > 3) 0 else {},
};
}
pub inline fn yzx(self: Self) Self {
return Self{
.x = self.y,
.y = self.z,
.z = self.x,
.w = if (nelem > 3) 0 else {},
};
}
pub inline fn yxz(self: Self) Self {
return Self{
.x = self.y,
.y = self.x,
.z = self.z,
.w = if (nelem > 3) 0 else {},
};
}
pub inline fn cross3(a: Self, b: Self) Self {
return zxy(sub(mul(zxy(a), b), mul(a, zxy(b))));
}
pub inline fn length3(self: Self) T {
return @sqrt(@maximum(std.math.epsilon(T), self.dot3(self)));
}
pub inline fn normalize3(self: Self) Self {
return self.divvs(self.length3());
}
} else struct {};
};
}
test "vec" {
const boop = Vec3i{ .x = 1, .y = 2, .z = 3 };
const bop = Vec3i{ .x = 1 };
try std.testing.expectEqual(@as(i32, 2), boop.add(bop).x);
try std.testing.expectEqual(@as(i32, 6), boop.sum());
}