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), ); } };