Files
voxel-game/src/math/Matrix4x4.zig

284 lines
10 KiB
Zig

const Vector3 = @import("Vector3.zig").Vector3;
const Vector4 = @import("Vector4.zig").Vector4;
const Quaternion = @import("Quaternion.zig").Quaternion;
pub const Matrix4x4 = extern struct {
i: Vector4,
j: Vector4,
k: Vector4,
t: Vector4,
pub const identity = Matrix4x4.init(
// zig fmt: off
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
// zig fmt: on
);
// --- INIT ---
pub inline fn init(
// zig fmt: off
ix: f32, iy: f32, iz: f32, iw: f32,
jx: f32, jy: f32, jz: f32, jw: f32,
kx: f32, ky: f32, kz: f32, kw: f32,
tx: f32, ty: f32, tz: f32, tw: f32,
// zig fmt: on
) Matrix4x4 {
return .{
.i = .init(ix, iy, iz, iw),
.j = .init(jx, jy, jz, jw),
.k = .init(kx, ky, kz, kw),
.t = .init(tx, ty, tz, tw),
};
}
pub inline fn initArray(array: [16]f32) Matrix4x4 {
return .{
.i = .initArray(array[0..4].*),
.j = .initArray(array[4..8].*),
.k = .initArray(array[8..12].*),
.t = .initArray(array[12..16].*),
};
}
pub inline fn initVector4(i: Vector4, j: Vector4, k: Vector4, t: Vector4) Matrix4x4 {
return .{ .i = i, .j = j, .k = k, .t = t };
}
pub inline fn initTranslation(translation: Vector3) Matrix4x4 {
return .initVector4(
.unit_x,
.unit_y,
.unit_z,
translation.asVector4(1),
);
}
pub inline fn initRotation(rotation: Quaternion) Matrix4x4 {
const xx = rotation.vector.getX() * rotation.vector.getX();
const xy = rotation.vector.getX() * rotation.vector.getY();
const xz = rotation.vector.getX() * rotation.vector.getZ();
const xw = rotation.vector.getX() * rotation.vector.getW();
const yy = rotation.vector.getY() * rotation.vector.getY();
const yz = rotation.vector.getY() * rotation.vector.getZ();
const yw = rotation.vector.getY() * rotation.vector.getW();
const zz = rotation.vector.getZ() * rotation.vector.getZ();
const zw = rotation.vector.getZ() * rotation.vector.getW();
return .init(
// zig fmt: off
1 - 2 * (yy + zz), 2 * (xy + zw), 2 * (xz - yw), 0,
2 * (xy - zw), 1 - 2 * (xx + zz), 2 * (yz + xw), 0,
2 * (xz + yw), 2 * (yz - xw), 1 - 2 * (xx + yy), 0,
0, 0, 0, 1,
// zig fmt: on
);
}
pub inline fn initScale(scale: Vector3) Matrix4x4 {
return .init(
// zig fmt: off
scale.getX(), 0, 0, 0,
0, scale.getY(), 0, 0,
0, 0, scale.getZ(), 0,
0, 0, 0, 1,
// zig fmt: on
);
}
pub inline fn initTranslationRotationScale(
translation: Vector3,
rotation: Quaternion,
scale: Vector3,
) Matrix4x4 {
const xx = rotation.vector.getX() * rotation.vector.getX();
const xy = rotation.vector.getX() * rotation.vector.getY();
const xz = rotation.vector.getX() * rotation.vector.getZ();
const xw = rotation.vector.getX() * rotation.vector.getW();
const yy = rotation.vector.getY() * rotation.vector.getY();
const yz = rotation.vector.getY() * rotation.vector.getZ();
const yw = rotation.vector.getY() * rotation.vector.getW();
const zz = rotation.vector.getZ() * rotation.vector.getZ();
const zw = rotation.vector.getZ() * rotation.vector.getW();
const rotation_i = Vector4.init((1 - 2 * (yy + zz)), 2 * (xy + zw), 2 * (xz - yw), 0);
const rotation_j = Vector4.init(2 * (xy - zw), (1 - 2 * (xx + zz)), 2 * (yz + xw), 0);
const rotation_k = Vector4.init(2 * (xz + yw), 2 * (yz - xw), (1 - 2 * (xx + yy)), 0);
return .initVector4(
.mulScalar(rotation_i, scale.getX()),
.mulScalar(rotation_j, scale.getY()),
.mulScalar(rotation_k, scale.getZ()),
translation.asVector4(1),
);
}
// --- CONVERSION ---
pub inline fn asArray(self: Matrix4x4) [16]f32 {
return self.i.asArray() ++ self.j.asArray() ++ self.k.asArray() ++ self.t.asArray();
}
pub inline fn asVector4(self: Matrix4x4) [4]Vector4 {
return .{ self.i, self.j, self.k, self.t };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .initVector4(
.add(self.i, other.i),
.add(self.j, other.j),
.add(self.k, other.k),
.add(self.t, other.t),
);
}
pub inline fn sub(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .initVector4(
.sub(self.i, other.i),
.sub(self.j, other.j),
.sub(self.k, other.k),
.sub(self.t, other.t),
);
}
pub inline fn negate(self: Matrix4x4) Matrix4x4 {
return .initVector4(
.negate(self.i),
.negate(self.j),
.negate(self.k),
.negate(self.t),
);
}
pub inline fn mulScalar(self: Matrix4x4, scalar: f32) Matrix4x4 {
return .initVector4(
.mulScalar(self.i, scalar),
.mulScalar(self.j, scalar),
.mulScalar(self.k, scalar),
.mulScalar(self.t, scalar),
);
}
pub inline fn divScalar(self: Matrix4x4, scalar: f32) Matrix4x4 {
const inv_scalar = 1 / scalar;
return .initVector4(
.mulScalar(self.i, inv_scalar),
.mulScalar(self.j, inv_scalar),
.mulScalar(self.k, inv_scalar),
.mulScalar(self.t, inv_scalar),
);
}
// --- OTHER ---
pub inline fn mulMatrix(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .initVector4(
self.i.mulScalar(other.i.getX())
.add(self.j.mulScalar(other.i.getY()))
.add(self.k.mulScalar(other.i.getZ()))
.add(self.t.mulScalar(other.i.getW())),
self.i.mulScalar(other.j.getX())
.add(self.j.mulScalar(other.j.getY()))
.add(self.k.mulScalar(other.j.getZ()))
.add(self.t.mulScalar(other.j.getW())),
self.i.mulScalar(other.k.getX())
.add(self.j.mulScalar(other.k.getY()))
.add(self.k.mulScalar(other.k.getZ()))
.add(self.t.mulScalar(other.k.getW())),
self.i.mulScalar(other.t.getX())
.add(self.j.mulScalar(other.t.getY()))
.add(self.k.mulScalar(other.t.getZ()))
.add(self.t.mulScalar(other.t.getW())),
);
}
pub inline fn inverseAffine(self: Matrix4x4) Matrix4x4 {
// zig fmt: off
const det = self.i.getX() * self.j.getY() * self.k.getZ()
+ self.i.getY() * self.j.getZ() * self.k.getX()
+ self.i.getZ() * self.j.getX() * self.k.getY()
- self.i.getX() * self.j.getZ() * self.k.getY()
- self.i.getY() * self.j.getX() * self.k.getZ()
- self.i.getZ() * self.j.getY() * self.k.getX();
// zig fmt: on
const inv_det = 1 / det;
const i = Vector3.init(
self.j.getY() * self.k.getZ() - self.j.getZ() * self.k.getY(),
self.i.getZ() * self.k.getY() - self.i.getY() * self.k.getZ(),
self.i.getY() * self.j.getZ() - self.i.getZ() * self.j.getY(),
).mulScalar(inv_det);
const j = Vector3.init(
self.j.getZ() * self.k.getX() - self.j.getX() * self.k.getZ(),
self.i.getX() * self.k.getZ() - self.i.getZ() * self.k.getX(),
self.i.getZ() * self.j.getX() - self.i.getX() * self.j.getZ(),
).mulScalar(inv_det);
const k = Vector3.init(
self.j.getX() * self.k.getY() - self.j.getY() * self.k.getX(),
self.i.getY() * self.k.getX() - self.i.getX() * self.k.getY(),
self.i.getX() * self.j.getY() - self.i.getY() * self.j.getX(),
).mulScalar(inv_det);
const t = self.i.asVector3().mulScalar(self.t.getX())
.add(self.j.asVector3().mulScalar(self.t.getY()))
.add(self.k.asVector3().mulScalar(self.t.getZ()))
.negate();
return .initVector4(
i.asVector4(0),
j.asVector4(0),
k.asVector4(0),
t.asVector4(1),
);
}
pub inline fn inverseTransposeAffine(self: Matrix4x4) Matrix4x4 {
// zig fmt: off
const det = self.i.getX() * self.j.getY() * self.k.getZ()
+ self.i.getY() * self.j.getZ() * self.k.getX()
+ self.i.getZ() * self.j.getX() * self.k.getY()
- self.i.getX() * self.j.getZ() * self.k.getY()
- self.i.getY() * self.j.getX() * self.k.getZ()
- self.i.getZ() * self.j.getY() * self.k.getX();
// zig fmt: on
const inv_det = 1 / det;
const i = Vector3.init(
self.j.getY() * self.k.getZ() - self.j.getZ() * self.k.getY(),
self.j.getZ() * self.k.getX() - self.j.getX() * self.k.getZ(),
self.j.getX() * self.k.getY() - self.j.getY() * self.k.getX(),
).mulScalar(inv_det);
const j = Vector3.init(
self.i.getZ() * self.k.getY() - self.i.getY() * self.k.getZ(),
self.i.getX() * self.k.getZ() - self.i.getZ() * self.k.getX(),
self.i.getY() * self.k.getX() - self.i.getX() * self.k.getY(),
).mulScalar(inv_det);
const k = Vector3.init(
self.i.getY() * self.j.getZ() - self.i.getZ() * self.j.getY(),
self.i.getZ() * self.j.getX() - self.i.getX() * self.j.getZ(),
self.i.getX() * self.j.getY() - self.i.getY() * self.j.getX(),
).mulScalar(inv_det);
const t = self.i.asVector3().mulScalar(self.t.getX())
.add(self.j.asVector3().mulScalar(self.t.getY()))
.add(self.k.asVector3().mulScalar(self.t.getZ()))
.negate();
return .initVector4(
i.asVector4(0),
j.asVector4(0),
k.asVector4(0),
t.asVector4(1),
);
}
};