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

82 lines
3.1 KiB
Zig

const std = @import("std");
const vec = @import("vec.zig");
const Vec3f = vec.Vec3f;
const Vec4f = vec.Vec4f;
// Intentionally use Vec4f to hopefully improve vectorization.
pub const Mat3f = Mat(3, Vec4f);
pub const Mat4f = Mat(4, Vec4f);
pub fn Mat(comptime nelem: comptime_int, comptime Vec: type) type {
return packed struct {
const Self = @This();
pub const nelem = nelem;
pub const zero = Self{};
pub const id = Self{
.c0 = .{ .x = 1 },
.c1 = .{ .y = 1 },
.c2 = if (nelem > 2 and Vec.nelem > 2) .{ .z = 1 } else {},
.c3 = if (nelem > 3 and Vec.nelem > 3) .{ .w = 1 } else {},
};
c0: Vec = .{},
c1: Vec = .{},
c2: if (nelem > 2) Vec else void = if (nelem > 2) .{} else {},
c3: if (nelem > 3) Vec else void = if (nelem > 3) .{} else {},
pub inline fn mulCol(self: Self, col: Vec) Vec {
const a = self.c0.mulvs(col.x);
const b = self.c1.mulvs(col.y);
const c = if (nelem > 2 and Vec.nelem > 2) self.c2.mulvs(col.z) else {};
const d = if (nelem > 3 and Vec.nelem > 2) self.c0.mulvs(col.w) else {};
return a.add(b).add(if (nelem > 2) if (nelem > 3) c.add(d) else c else Vec.zero);
}
pub inline fn mul(a: Self, b: Self) Self {
return Self{
.c0 = a.mulCol(b.c0),
.c1 = a.mulCol(b.c1),
.c2 = if (nelem > 2) a.mulCol(b.c2) else {},
.c3 = if (nelem > 3) a.mulCol(b.c3) else {},
};
}
// Special methods specifically for Mat4f.
pub usingnamespace if (nelem == 4 and Vec == Vec4f) struct {
pub inline fn lookAt(eye: Vec4f, at: Vec4f, up: Vec4f) Self {
// right-handed (ew)
const f = at.sub(eye).normalize3();
const s = f.cross3(up).normalize3();
const u = s.cross3(f).normalize3();
const tx = -s.dot3(eye);
const ty = -u.dot3(eye);
const tz = f.dot3(eye);
return Self{
.c0 = .{ .x = s.x, .y = u.x, .z = -f.x, .w = 0 },
.c1 = .{ .x = s.y, .y = u.y, .z = -f.y, .w = 0 },
.c2 = .{ .x = s.z, .y = u.z, .z = -f.z, .w = 0 },
.c3 = .{ .x = tx, .y = ty, .z = tz, .w = 1 },
};
}
pub inline fn glPerspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) Self {
const t = std.math.tan(fov_y * 0.5);
var m = Mat(4, Vec4f).zero;
m.c0.x = 1.0 / (aspect * t);
m.c1.y = 1.0 / t;
m.c2.z = -1.0 * (z_far * z_near) / (z_far - z_near);
m.c3.z = -2.0 * (z_far * z_near) / (z_far - z_near);
return m;
}
pub inline fn vkPerspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) Self {
var m = glPerspective(fov_y, aspect, z_near, z_far);
m.c1.y *= -1.0;
return m;
}
} else struct {};
};
}