618 lines
19 KiB
Zig
618 lines
19 KiB
Zig
const std = @import("std");
|
|
const zm = @import("zmath");
|
|
const math = std.math;
|
|
|
|
// vector versions.
|
|
pub const f32x4 = @Vector(4, f32); // __m128_int
|
|
pub const f32x8 = @Vector(8, f32); // __m256_int
|
|
pub const f32x16 = @Vector(16, f32); // __m512_int
|
|
|
|
pub const f32x4_zero = std.mem.zeroes(@Vector(4, f32));
|
|
pub const f32x8_zero = std.mem.zeroes(@Vector(8, f32));
|
|
pub const f32x16_zero = std.mem.zeroes(@Vector(16, f32));
|
|
|
|
pub const Rayf = RayType(Vectorf);
|
|
|
|
pub fn matToScalef(mat: anytype) Vectorf {
|
|
const x = Vectorf.new(mat[0][0], mat[0][1], mat[0][2]).length();
|
|
const y = Vectorf.new(mat[1][0], mat[1][1], mat[1][2]).length();
|
|
const z = Vectorf.new(mat[2][0], mat[2][1], mat[2][2]).length();
|
|
|
|
return Vectorf.new(x, y, z);
|
|
}
|
|
|
|
pub fn RayType(comptime T: type) type {
|
|
return struct {
|
|
start: T,
|
|
dir: T,
|
|
};
|
|
}
|
|
|
|
pub fn clamp(x: anytype, min: anytype, max: anytype) @TypeOf(x) {
|
|
if (x < min)
|
|
return min;
|
|
if (x > max)
|
|
return max;
|
|
return x;
|
|
}
|
|
|
|
pub fn matFromEulerAngles(x: f32, y: f32, z: f32) Mat {
|
|
return zm.matFromRollPitchYaw(y, z, x);
|
|
}
|
|
|
|
pub fn Radians(comptime T: type) type {
|
|
return struct {
|
|
value: T,
|
|
|
|
pub fn fromDegrees(f: anytype) @This() {
|
|
return .{ .value = f };
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn radians(f: anytype) @TypeOf(f) {
|
|
return f * math.pi / 180.0;
|
|
}
|
|
|
|
pub fn fabs(x: anytype) @TypeOf(x) {
|
|
if (x < 0)
|
|
return -x;
|
|
return x;
|
|
}
|
|
|
|
pub fn Vector2Type(comptime T: type, comptime typeName: []const u8) type {
|
|
return extern struct {
|
|
x: T = 0,
|
|
y: T = 0,
|
|
|
|
pub const VectorTypeName = typeName;
|
|
|
|
pub const Ones = @This(){ .x = 1, .y = 1 };
|
|
pub const Zeroes = @This(){ .x = 0, .y = 0 };
|
|
|
|
pub inline fn new(x: T, y: T) @This() {
|
|
return .{
|
|
.x = x,
|
|
.y = y,
|
|
};
|
|
}
|
|
|
|
pub inline fn add(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x + other.x,
|
|
.y = self.y + other.y,
|
|
};
|
|
}
|
|
|
|
pub inline fn sub(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x - other.x,
|
|
.y = self.y - other.y,
|
|
};
|
|
}
|
|
|
|
pub inline fn vmul(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x * other.x,
|
|
.y = self.y * other.y,
|
|
};
|
|
}
|
|
|
|
pub inline fn fmul(self: @This(), other: T) @This() {
|
|
return .{
|
|
.x = self.x * other,
|
|
.y = self.y * other,
|
|
};
|
|
}
|
|
|
|
pub inline fn dot(self: @This(), other: @This()) T {
|
|
return self.x * other.x + self.y * other.y;
|
|
}
|
|
|
|
pub inline fn equals(self: @This(), other: @This()) bool {
|
|
return self.x == other.x and self.y == other.y;
|
|
}
|
|
|
|
pub inline fn length(self: @This()) T {
|
|
return std.math.sqrt(self.x * self.x + self.y * self.y);
|
|
}
|
|
|
|
pub inline fn swizzleYX(self: @This()) @This() {
|
|
return .{ .x = self.y, .y = self.x };
|
|
}
|
|
|
|
pub inline fn normalize(self: @This()) @This() {
|
|
if (fabs(self.x) <= 0.0001 and fabs(self.y) <= 0.0001) {
|
|
return .{ .x = 0, .y = 0 };
|
|
}
|
|
const len = std.math.sqrt(self.x * self.x + self.y * self.y);
|
|
|
|
if (len < 0.00001)
|
|
return .{ .x = 0, .y = 0 };
|
|
|
|
return .{
|
|
.x = self.x / len,
|
|
.y = self.y / len,
|
|
};
|
|
}
|
|
|
|
pub inline fn negate(self: @This()) @This() {
|
|
return .{ .x = -self.x, .y = self.y };
|
|
}
|
|
|
|
pub inline fn cross(self: @This(), other: @This()) T {
|
|
return self.x * other.y - self.y * other.x;
|
|
}
|
|
|
|
pub inline fn removeComponent(self: @This(), other: @This()) @This() {
|
|
return self.sub(other.fmul(self.dot(other)));
|
|
}
|
|
|
|
pub inline fn from(o: anytype) @This() {
|
|
const OType: std.builtin.Type = @typeInfo(@TypeOf(o.x));
|
|
switch (@typeInfo(T)) {
|
|
.int => {
|
|
switch (OType) {
|
|
.int => {
|
|
// convert integer into integer
|
|
return .{
|
|
.x = @intCast(o.x),
|
|
.y = @intCast(o.y),
|
|
};
|
|
},
|
|
.float => {
|
|
// convert float into float
|
|
return .{
|
|
.x = @intFromFloat(o.x),
|
|
.y = @intFromFloat(o.y),
|
|
};
|
|
},
|
|
else => {
|
|
@compileError("Invalid vector type conversion");
|
|
},
|
|
}
|
|
},
|
|
.float => {
|
|
switch (OType) {
|
|
.int => {
|
|
// convert integer into float
|
|
return .{
|
|
.x = @floatFromInt(o.x),
|
|
.y = @floatFromInt(o.y),
|
|
};
|
|
},
|
|
.float => {
|
|
// convert float
|
|
return .{
|
|
.x = @floatCast(o.x),
|
|
.y = @floatCast(o.y),
|
|
};
|
|
},
|
|
else => {
|
|
// convert float into float
|
|
@compileError("Invalid vector type conversion");
|
|
},
|
|
}
|
|
},
|
|
else => {
|
|
@compileError("Invalid vector type conversion");
|
|
},
|
|
}
|
|
@compileError("Invalid vector conversion");
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn Vector3Type(comptime T: type, comptime typeName: []const u8) type {
|
|
return extern struct {
|
|
x: T = 0,
|
|
y: T = 0,
|
|
z: T = 0,
|
|
|
|
pub const VectorTypeName = typeName;
|
|
|
|
pub const Ones = @This(){ .x = 1, .y = 1, .z = 1 };
|
|
pub const Zeroes = @This(){ .x = 0, .y = 0, .z = 0 };
|
|
|
|
pub const Up = @This(){ .y = 1 };
|
|
pub const Right = @This(){ .x = 1 };
|
|
pub const Forward = @This(){ .z = 1 };
|
|
|
|
pub inline fn new(x: T, y: T, z: T) @This() {
|
|
return .{
|
|
.x = x,
|
|
.y = y,
|
|
.z = z,
|
|
};
|
|
}
|
|
|
|
pub inline fn fromInt(t: anytype) @This() {
|
|
return .{ .x = t, .y = t, .z = t };
|
|
}
|
|
|
|
// easing functions
|
|
pub inline fn drainToZero(self: @This(), o: anytype) @This() {
|
|
return self.drain(o, Zeroes);
|
|
}
|
|
|
|
pub inline fn drain(self: @This(), o: anytype, target: anytype) @This() {
|
|
return .{
|
|
.x = drainElement(self.x, o.x, target.x),
|
|
.y = drainElement(self.y, o.y, target.y),
|
|
.z = drainElement(self.z, o.z, target.z),
|
|
};
|
|
}
|
|
|
|
inline fn drainElement(a: anytype, v: anytype, t: anytype) @TypeOf(a) {
|
|
if (a > t) {
|
|
return @max(t, a - v);
|
|
} else {
|
|
return @min(t, a + v);
|
|
}
|
|
}
|
|
|
|
// array functions.
|
|
pub inline fn toArr3(self: @This()) [3]T {
|
|
return .{ self.x, self.y, self.z };
|
|
}
|
|
|
|
pub inline fn fromArr3(v: [3]f32) @This() {
|
|
return .{ .x = v[0], .y = v[1], .z = v[2] };
|
|
}
|
|
|
|
pub inline fn toZm(self: @This()) zm.Vec {
|
|
return .{ self.x, self.y, self.z, 1.0 };
|
|
}
|
|
|
|
pub inline fn fromZm(vec: zm.Vec) @This() {
|
|
return @This().new(vec[0], vec[1], vec[2]);
|
|
}
|
|
|
|
pub inline fn add(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x + other.x,
|
|
.y = self.y + other.y,
|
|
.z = self.z + other.z,
|
|
};
|
|
}
|
|
|
|
pub inline fn sub(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x - other.x,
|
|
.y = self.y - other.y,
|
|
.z = self.z - other.z,
|
|
};
|
|
}
|
|
|
|
pub inline fn vmul(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x * other.x,
|
|
.y = self.y * other.y,
|
|
.z = self.z * other.z,
|
|
};
|
|
}
|
|
|
|
pub inline fn fmul(self: @This(), other: T) @This() {
|
|
return .{
|
|
.x = self.x * other,
|
|
.y = self.y * other,
|
|
.z = self.z * other,
|
|
};
|
|
}
|
|
|
|
pub inline fn dot(self: @This(), other: @This()) T {
|
|
return self.x * other.x + self.y * other.y + self.z * other.z;
|
|
}
|
|
|
|
pub inline fn equals(self: @This(), other: @This()) bool {
|
|
return self.x == other.x and self.y == self.y and self.z == self.z;
|
|
}
|
|
|
|
pub inline fn length(self: @This()) T {
|
|
return std.math.sqrt(self.x * self.x + self.z * self.z + self.y * self.y);
|
|
}
|
|
|
|
pub inline fn swizzleYZX(self: @This()) @This() {
|
|
return .{ .x = self.y, .y = self.z, .z = self.x };
|
|
}
|
|
|
|
pub inline fn swizzleYXZ(self: @This()) @This() {
|
|
return .{ .x = self.y, .y = self.x, .z = self.z };
|
|
}
|
|
|
|
pub inline fn swizzleZXY(self: @This()) @This() {
|
|
return .{ .x = self.z, .y = self.x, .z = self.y };
|
|
}
|
|
|
|
pub inline fn swizzleZYX(self: @This()) @This() {
|
|
return .{ .x = self.z, .y = self.y, .z = self.x };
|
|
}
|
|
|
|
pub inline fn swizzleXZY(self: @This()) @This() {
|
|
return .{ .x = self.x, .y = self.z, .z = self.y };
|
|
}
|
|
|
|
pub inline fn lengthXZ(self: @This()) T {
|
|
return std.math.sqrt(self.x * self.x + self.z * self.z);
|
|
}
|
|
|
|
pub inline fn normalize(self: @This()) @This() {
|
|
if (fabs(self.x) <= 0.0001 and fabs(self.y) <= 0.0001 and fabs(self.z) <= 0.0001) {
|
|
return .{ .x = 0, .y = 0, .z = 0 };
|
|
}
|
|
const len = std.math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
|
|
|
|
if (len < 0.00001)
|
|
return .{ .x = 0, .y = 0, .z = 0 };
|
|
|
|
return .{
|
|
.x = self.x / len,
|
|
.y = self.y / len,
|
|
.z = self.z / len,
|
|
};
|
|
}
|
|
|
|
pub inline fn fromArray(o: anytype) @This() {
|
|
return .{
|
|
.x = o[0],
|
|
.y = o[1],
|
|
.z = o[2],
|
|
};
|
|
}
|
|
|
|
pub inline fn clampAllAbs(self: @This(), abs: anytype) @This() {
|
|
return .{
|
|
.x = std.math.clamp(self.x, -abs, abs),
|
|
.y = std.math.clamp(self.y, -abs, abs),
|
|
.z = std.math.clamp(self.z, -abs, abs),
|
|
};
|
|
}
|
|
|
|
pub inline fn cross(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.y * other.z - self.z * other.y,
|
|
.y = self.z * other.x - self.x * other.z,
|
|
.z = self.x * other.y - self.y * other.x,
|
|
};
|
|
}
|
|
|
|
pub fn lerp(self: @This(), other: @This(), alpha: anytype) @This() {
|
|
return .{
|
|
.x = std.math.lerp(self.x, other.x, alpha),
|
|
.y = std.math.lerp(self.y, other.y, alpha),
|
|
.z = std.math.lerp(self.z, other.z, alpha),
|
|
};
|
|
}
|
|
|
|
pub inline fn clampAll(self: @This(), lower: anytype, upper: anytype) @This() {
|
|
return .{
|
|
.x = std.math.clamp(self.x, -lower, upper),
|
|
.y = std.math.clamp(self.y, -lower, upper),
|
|
.z = std.math.clamp(self.z, -lower, upper),
|
|
};
|
|
}
|
|
|
|
pub inline fn from(o: anytype) @This() {
|
|
const OType: std.builtin.Type = @typeInfo(@TypeOf(o.x));
|
|
switch (@typeInfo(T)) {
|
|
.Int => {
|
|
switch (OType) {
|
|
.Int => {
|
|
// convert integer into integer
|
|
return .{
|
|
.x = @intCast(o.x),
|
|
.y = @intCast(o.y),
|
|
.z = @intCast(o.z),
|
|
};
|
|
},
|
|
.Float => {
|
|
// convert float into float
|
|
return .{
|
|
.x = @intFromFloat(o.x),
|
|
.y = @intFromFloat(o.y),
|
|
.z = @intFromFloat(o.z),
|
|
};
|
|
},
|
|
else => {
|
|
@compileError("Invalid vector type conversion");
|
|
},
|
|
}
|
|
},
|
|
.Float => {
|
|
switch (OType) {
|
|
.Int => {
|
|
// convert integer into float
|
|
return .{
|
|
.x = @floatFromInt(o.x),
|
|
.y = @floatFromInt(o.y),
|
|
.z = @floatFromInt(o.z),
|
|
};
|
|
},
|
|
.Float => {
|
|
// convert float
|
|
return .{
|
|
.x = @floatCast(o.x),
|
|
.y = @floatCast(o.y),
|
|
.z = @floatCast(o.z),
|
|
};
|
|
},
|
|
else => {
|
|
// convert float into float
|
|
@compileError("Invalid vector type conversion");
|
|
},
|
|
}
|
|
},
|
|
else => {
|
|
@compileError("Invalid vector type conversion");
|
|
},
|
|
}
|
|
@compileError("Invalid vector conversion");
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn Vector4Type(comptime T: type) type {
|
|
return extern struct {
|
|
x: T = 0,
|
|
y: T = 0,
|
|
z: T = 0,
|
|
w: T = 0,
|
|
|
|
pub const Ones = @This(){ .x = 1, .y = 1, .z = 1 };
|
|
pub const Zeroes = @This(){ .x = 0, .y = 0, .z = 0 };
|
|
|
|
pub inline fn from(o: anytype) @This() {
|
|
return .{ .x = o.x, .y = o.y, .z = o.z, .w = o.w };
|
|
}
|
|
|
|
pub inline fn new(x: T, y: T, z: T, w: T) @This() {
|
|
return .{
|
|
.x = x,
|
|
.y = y,
|
|
.z = z,
|
|
.w = w,
|
|
};
|
|
}
|
|
|
|
pub inline fn add(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x + other.x,
|
|
.y = self.y + other.y,
|
|
.z = self.z + other.z,
|
|
.w = self.w + other.w,
|
|
};
|
|
}
|
|
|
|
pub inline fn sub(self: @This(), other: @This()) @This() {
|
|
return .{
|
|
.x = self.x - other.x,
|
|
.y = self.y - other.y,
|
|
.z = self.z - other.z,
|
|
.w = self.w - other.w,
|
|
};
|
|
}
|
|
|
|
pub inline fn normalize(self: @This()) @This() {
|
|
const len = std.math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w);
|
|
|
|
return .{
|
|
.x = self.x / len,
|
|
.y = self.y / len,
|
|
.z = self.z / len,
|
|
.w = self.w / len,
|
|
};
|
|
}
|
|
};
|
|
}
|
|
pub const Vector4 = Vector4Type(f64);
|
|
pub const Vector4f = Vector4Type(f32);
|
|
|
|
pub const Vector = Vector3Type(f64, "Vector");
|
|
pub const Vectorf = Vector3Type(f32, "Vectorf");
|
|
pub const Vector2f = Vector2Type(f32, "Vector2f");
|
|
pub const Vector2 = Vector2Type(f64, "Vector2");
|
|
|
|
pub const Vector2i = Vector2Type(i32, "Vector2i");
|
|
pub const Vector2c = Vector2Type(c_int, "Vector2c");
|
|
pub const Vector2u = Vector2Type(u32, "Vector2u");
|
|
pub const Vector2l = Vector2Type(i64, "Vector2l");
|
|
|
|
pub const EulerAngles = Vectorf;
|
|
pub const Quat = zm.Quat;
|
|
pub const Mat = zm.Mat;
|
|
pub const Transform = zm.Mat;
|
|
|
|
pub fn matGetPosition(m: Mat) Vectorf {
|
|
const vec: Vectorf = .{};
|
|
return Vectorf.fromZm(zm.mul(vec.toZm(), m));
|
|
}
|
|
|
|
pub fn matToRotation(m: Mat) Rotation {
|
|
const r: Rotation = .{ .quat = zm.matToQuat(m) };
|
|
return r;
|
|
}
|
|
|
|
pub const Rotation = struct {
|
|
quat: Quat = zm.qidentity(),
|
|
|
|
pub fn init() @This() {
|
|
return .{};
|
|
}
|
|
|
|
pub fn add(self: @This(), other: @This()) Rotation {
|
|
const m1 = zm.quatToMat(self.quat);
|
|
const m2 = zm.quatToMat(other.quat);
|
|
|
|
const r = zm.mul(m1, m2);
|
|
return .{ .quat = zm.matToQuat(r) };
|
|
}
|
|
|
|
pub fn eulerX(o: f32) @This() {
|
|
return .{
|
|
.quat = zm.matToQuat(zm.rotationX((o))),
|
|
};
|
|
}
|
|
|
|
pub fn eulerY(o: f32) @This() {
|
|
return .{
|
|
.quat = zm.matToQuat(zm.rotationY((o))),
|
|
};
|
|
}
|
|
|
|
pub fn eulerZ(o: f32) @This() {
|
|
return .{
|
|
.quat = zm.matToQuat(zm.rotationZ((o))),
|
|
};
|
|
}
|
|
|
|
pub fn up(self: @This()) Vectorf {
|
|
return self.rotateVector(Vectorf.Up);
|
|
}
|
|
|
|
pub fn forward(self: @This()) Vectorf {
|
|
return self.rotateVector(Vectorf.Forward);
|
|
}
|
|
|
|
pub fn right(self: @This()) Vectorf {
|
|
return self.rotateVector(Vectorf.Right);
|
|
}
|
|
|
|
pub fn rotateVector(self: @This(), other: Vectorf) Vectorf {
|
|
return Vectorf.fromZm(
|
|
zm.mul(
|
|
other.toZm(),
|
|
zm.quatToMat(self.quat),
|
|
),
|
|
);
|
|
}
|
|
};
|
|
|
|
pub fn lerp(a: f32, b: f32, t: f32) f32 {
|
|
return a + t * (b - a);
|
|
}
|
|
|
|
pub fn simdVec4ToVec(vec: zm.Vec) Vector4f {
|
|
return .{
|
|
.x = vec[0],
|
|
.y = vec[1],
|
|
.z = vec[2],
|
|
.w = vec[3],
|
|
};
|
|
}
|
|
|
|
pub fn easeLinear(c: f32, t: f32, dt: f64, rate: f32) f32 {
|
|
const d = rate * @as(f32, @floatCast(dt));
|
|
|
|
if (c > t) {
|
|
return @max(c - d, t);
|
|
} else if (c < t) {
|
|
return @min(c + d, t);
|
|
} else {
|
|
return t;
|
|
}
|
|
}
|
|
|
|
pub fn rollingAverage(average: *f64, newValue: f64, sampleCount: f64) void {
|
|
average.* = average.* - (average.* / sampleCount) + newValue / sampleCount;
|
|
}
|