235 lines
6.9 KiB
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());
|
|
}
|