From 4cbf151fd95da6b5dc78c43a070d3adeadde0342 Mon Sep 17 00:00:00 2001 From: Szymon Nowakowski Date: Thu, 13 Nov 2025 02:22:22 +0100 Subject: [PATCH] Refactor math for no good reason; I just really like math --- src/math.zig | 1 + src/math/Matrix4x4.zig | 254 ++++++++++++++++++++++------------------ src/math/Quaternion.zig | 141 ++++++++++++++-------- src/math/Vector2.zig | 146 +++++++++++++++++++++++ src/math/Vector3.zig | 102 +++++++++++++--- src/math/Vector4.zig | 86 ++++++++++---- 6 files changed, 529 insertions(+), 201 deletions(-) create mode 100644 src/math/Vector2.zig diff --git a/src/math.zig b/src/math.zig index 9616e14..e9926a4 100644 --- a/src/math.zig +++ b/src/math.zig @@ -1,4 +1,5 @@ pub const Matrix4x4 = @import("math/Matrix4x4.zig").Matrix4x4; pub const Quaternion = @import("math/Quaternion.zig").Quaternion; +pub const Vector2 = @import("math/Vector2.zig").Vector2; pub const Vector3 = @import("math/Vector3.zig").Vector3; pub const Vector4 = @import("math/Vector4.zig").Vector4; diff --git a/src/math/Matrix4x4.zig b/src/math/Matrix4x4.zig index 13ec838..38632c5 100644 --- a/src/math/Matrix4x4.zig +++ b/src/math/Matrix4x4.zig @@ -17,6 +17,8 @@ pub const Matrix4x4 = extern struct { // zig fmt: on ); + // --- INIT --- + pub inline fn init( // zig fmt: off ix: f32, iy: f32, iz: f32, iw: f32, @@ -26,147 +28,173 @@ pub const Matrix4x4 = extern struct { // zig fmt: on ) Matrix4x4 { return .{ - .i = .{ .vector = .{ ix, iy, iz, iw } }, - .j = .{ .vector = .{ jx, jy, jz, jw } }, - .k = .{ .vector = .{ kx, ky, kz, kw } }, - .t = .{ .vector = .{ tx, ty, tz, tw } }, + .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 initVector(i: Vector4, j: Vector4, k: Vector4, t: Vector4) Matrix4x4 { + 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 .{ - .i = .{ .vector = .{ 1, 0, 0, 0 } }, - .j = .{ .vector = .{ 0, 1, 0, 0 } }, - .k = .{ .vector = .{ 0, 0, 1, 0 } }, - .t = .{ .vector = translation.vector ++ .{1} }, - }; + return .initVector4( + .unit_x, + .unit_y, + .unit_z, + translation.asVector4(1), + ); } pub inline fn initRotation(rotation: Quaternion) Matrix4x4 { - const xx = rotation.getX() * rotation.getX(); - const xy = rotation.getX() * rotation.getY(); - const xz = rotation.getX() * rotation.getZ(); - const xw = rotation.getX() * rotation.getW(); - const yy = rotation.getY() * rotation.getY(); - const yz = rotation.getY() * rotation.getZ(); - const yw = rotation.getY() * rotation.getW(); - const zz = rotation.getZ() * rotation.getZ(); - const zw = rotation.getZ() * rotation.getW(); + 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 .{ - .i = .{ .vector = .{ 1 - 2 * (yy + zz), 2 * (xy + zw), 2 * (xz - yw), 0 } }, - .j = .{ .vector = .{ 2 * (xy - zw), 1 - 2 * (xx + zz), 2 * (yz + xw), 0 } }, - .k = .{ .vector = .{ 2 * (xz + yw), 2 * (yz - xw), 1 - 2 * (xx + yy), 0 } }, - .t = .{ .vector = .{ 0, 0, 0, 1 } }, - }; + 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 .{ - .i = .{ .vector = .{ scale.getX(), 0, 0, 0 } }, - .j = .{ .vector = .{ 0, scale.getY(), 0, 0 } }, - .k = .{ .vector = .{ 0, 0, scale.getZ(), 0 } }, - .t = .{ .vector = .{ 0, 0, 0, 1 } }, - }; + 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.getX() * rotation.getX(); - const xy = rotation.getX() * rotation.getY(); - const xz = rotation.getX() * rotation.getZ(); - const xw = rotation.getX() * rotation.getW(); - const yy = rotation.getY() * rotation.getY(); - const yz = rotation.getY() * rotation.getZ(); - const yw = rotation.getY() * rotation.getW(); - const zz = rotation.getZ() * rotation.getZ(); - const zw = rotation.getZ() * rotation.getW(); + 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 scale_x: Vector4.Vector = @splat(scale.getX()); - const scale_y: Vector4.Vector = @splat(scale.getY()); - const scale_z: Vector4.Vector = @splat(scale.getZ()); + 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); - const rotation_i: Vector4.Vector = .{ (1 - 2 * (yy + zz)), 2 * (xy + zw), 2 * (xz - yw), 0 }; - const rotation_j: Vector4.Vector = .{ 2 * (xy - zw), (1 - 2 * (xx + zz)), 2 * (yz + xw), 0 }; - const rotation_k: Vector4.Vector = .{ 2 * (xz + yw), 2 * (yz - xw), (1 - 2 * (xx + yy)), 0 }; - - return .{ - .i = .{ .vector = scale_x * rotation_i }, - .j = .{ .vector = scale_y * rotation_j }, - .k = .{ .vector = scale_z * rotation_k }, - .t = .{ .vector = translation.vector ++ .{1} }, - }; + return .initVector4( + Vector4.mulScalar(rotation_i, scale.getX()), + Vector4.mulScalar(rotation_j, scale.getY()), + Vector4.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 .{ - .i = .{ .vector = self.i.vector + other.i.vector }, - .j = .{ .vector = self.j.vector + other.j.vector }, - .k = .{ .vector = self.k.vector + other.k.vector }, - .t = .{ .vector = self.t.vector + other.t.vector }, - }; + return .initVector4( + Vector4.add(self.i, other.i), + Vector4.add(self.j, other.j), + Vector4.add(self.k, other.k), + Vector4.add(self.t, other.t), + ); } pub inline fn sub(self: Matrix4x4, other: Matrix4x4) Matrix4x4 { - return .{ - .i = .{ .vector = self.i.vector - other.i.vector }, - .j = .{ .vector = self.j.vector - other.j.vector }, - .k = .{ .vector = self.k.vector - other.k.vector }, - .t = .{ .vector = self.t.vector - other.t.vector }, - }; - } - - pub inline fn mulScalar(self: Matrix4x4, scalar: f32) Matrix4x4 { - const scalar_vector: Vector4.Vector = @splat(scalar); - return .{ - .i = .{ .vector = self.i.vector * scalar_vector }, - .j = .{ .vector = self.j.vector * scalar_vector }, - .k = .{ .vector = self.k.vector * scalar_vector }, - .t = .{ .vector = self.t.vector * scalar_vector }, - }; - } - - pub inline fn divScalar(self: Matrix4x4, scalar: f32) Matrix4x4 { - const inv_scalar_vector: Vector4.Vector = @splat(1 / scalar); - return .{ - .i = .{ .vector = self.i * inv_scalar_vector }, - .j = .{ .vector = self.j * inv_scalar_vector }, - .k = .{ .vector = self.k * inv_scalar_vector }, - .t = .{ .vector = self.t * inv_scalar_vector }, - }; + return .initVector4( + Vector4.sub(self.i, other.i), + Vector4.sub(self.j, other.j), + Vector4.sub(self.k, other.k), + Vector4.sub(self.t, other.t), + ); } pub inline fn negate(self: Matrix4x4) Matrix4x4 { - return .{ - .i = .{ .vector = -self.i.vector }, - .j = .{ .vector = -self.j.vector }, - .k = .{ .vector = -self.k.vector }, - .t = .{ .vector = -self.t.vector }, - }; + return .initVector4( + Vector4.negate(self.i), + Vector4.negate(self.j), + Vector4.negate(self.k), + Vector4.negate(self.t), + ); } + pub inline fn mulScalar(self: Matrix4x4, scalar: f32) Matrix4x4 { + return .initVector4( + Vector4.mulScalar(self.i, scalar), + Vector4.mulScalar(self.j, scalar), + Vector4.mulScalar(self.k, scalar), + Vector4.mulScalar(self.t, scalar), + ); + } + + pub inline fn divScalar(self: Matrix4x4, scalar: f32) Matrix4x4 { + const inv_scalar = 1 / scalar; + return .initVector4( + Vector4.mulScalar(self.i, inv_scalar), + Vector4.mulScalar(self.j, inv_scalar), + Vector4.mulScalar(self.k, inv_scalar), + Vector4.mulScalar(self.t, inv_scalar), + ); + } + + // --- OTHER --- + pub inline fn mulMatrix(self: Matrix4x4, other: Matrix4x4) Matrix4x4 { - return .{ - .i = self.i.mulScalar(other.i.getX()) + 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())), - .j = self.i.mulScalar(other.j.getX()) + 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())), - .k = self.i.mulScalar(other.k.getX()) + 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())), - .t = self.i.mulScalar(other.t.getX()) + 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 { @@ -203,12 +231,12 @@ pub const Matrix4x4 = extern struct { .add(self.k.asVector3().mulScalar(self.t.getZ())) .negate(); - return .{ - .i = .{ .vector = i ++ .{0} }, - .j = .{ .vector = j ++ .{0} }, - .k = .{ .vector = k ++ .{0} }, - .t = .{ .vector = t ++ .{1} }, - }; + return .initVector4( + i.asVector4(0), + j.asVector4(0), + k.asVector4(0), + t.asVector4(1), + ); } pub inline fn inverseTransposeAffine(self: Matrix4x4) Matrix4x4 { @@ -245,15 +273,11 @@ pub const Matrix4x4 = extern struct { .add(self.k.asVector3().mulScalar(self.t.getZ())) .negate(); - return .{ - .i = .{ .vector = i ++ .{0} }, - .j = .{ .vector = j ++ .{0} }, - .k = .{ .vector = k ++ .{0} }, - .t = .{ .vector = t ++ .{1} }, - }; - } - - pub inline fn asArray(self: Matrix4x4) [16]f32 { - return @bitCast(self); + return .initVector4( + i.asVector4(0), + j.asVector4(0), + k.asVector4(0), + t.asVector4(1), + ); } }; diff --git a/src/math/Quaternion.zig b/src/math/Quaternion.zig index 2776637..634b255 100644 --- a/src/math/Quaternion.zig +++ b/src/math/Quaternion.zig @@ -1,114 +1,155 @@ -const std = @import("std"); +const Vector3 = @import("Vector3.zig").Vector3; +const Vector4 = @import("Vector4.zig").Vector4; pub const Quaternion = extern struct { - vector: Vector, + vector: Vector4, - pub const Vector = @Vector(4, f32); - - pub const zero = Quaternion.init(0, 0, 0, 0); - pub const one = Quaternion.init(1, 1, 1, 1); pub const identity = Quaternion.init(0, 0, 0, 1); + // --- INIT --- + pub inline fn init(x: f32, y: f32, z: f32, w: f32) Quaternion { - return .{ .vector = .{ x, y, z, w } }; + return .{ .vector = .init(x, y, z, w) }; + } + + pub inline fn initArray(array: [4]f32) Quaternion { + return .{ .vector = .initArray(array) }; + } + + pub inline fn initVector4(vector: Vector4) Quaternion { + return .{ .vector = vector }; } pub inline fn initRotationXY(angle_rad: f32) Quaternion { const half_angle_rad = 0.5 * angle_rad; - return .{ .vector = .{ 0, 0, @sin(half_angle_rad), @cos(half_angle_rad) } }; + const c = @cos(half_angle_rad); + const s = @sin(half_angle_rad); + return .init(0, 0, s, c); } pub inline fn initRotationXZ(angle_rad: f32) Quaternion { const half_angle_rad = 0.5 * angle_rad; - return .{ .vector = .{ 0, -@sin(half_angle_rad), 0, @cos(half_angle_rad) } }; + const c = @cos(half_angle_rad); + const s = @sin(half_angle_rad); + return .init(0, -s, 0, c); } pub inline fn initRotationYX(angle_rad: f32) Quaternion { const half_angle_rad = 0.5 * angle_rad; - return .{ .vector = .{ 0, 0, -@sin(half_angle_rad), @cos(half_angle_rad) } }; + const c = @cos(half_angle_rad); + const s = @sin(half_angle_rad); + return .init(0, 0, -s, c); } pub inline fn initRotationYZ(angle_rad: f32) Quaternion { const half_angle_rad = 0.5 * angle_rad; - return .{ .vector = .{ @sin(half_angle_rad), 0, 0, @cos(half_angle_rad) } }; + const c = @cos(half_angle_rad); + const s = @sin(half_angle_rad); + return .init(s, 0, 0, c); } pub inline fn initRotationZX(angle_rad: f32) Quaternion { const half_angle_rad = 0.5 * angle_rad; - return .{ .vector = .{ 0, @sin(half_angle_rad), 0, @cos(half_angle_rad) } }; + const c = @cos(half_angle_rad); + const s = @sin(half_angle_rad); + return .init(0, s, 0, c); } pub inline fn initRotationZY(angle_rad: f32) Quaternion { const half_angle_rad = 0.5 * angle_rad; - return .{ .vector = .{ -@sin(half_angle_rad), 0, 0, @cos(half_angle_rad) } }; + const c = @cos(half_angle_rad); + const s = @sin(half_angle_rad); + return .init(-s, 0, 0, c); } - pub inline fn getX(self: Quaternion) f32 { - return self.vector[0]; + // --- CONVERSION --- + + pub inline fn asArray(self: Quaternion) [4]f32 { + return self.vector.vector; } - pub inline fn getY(self: Quaternion) f32 { - return self.vector[1]; + pub inline fn asVector4(self: Quaternion) Vector4 { + return self.vector; } - pub inline fn getZ(self: Quaternion) f32 { - return self.vector[2]; + // --- ACCESSORS --- + + pub inline fn getVector(self: Quaternion) Vector3 { + return self.vector.asVector3(); } - pub inline fn getW(self: Quaternion) f32 { - return self.vector[3]; + pub inline fn getScalar(self: Quaternion) f32 { + return self.vector.getW(); } - pub inline fn setX(self: Quaternion, x: f32) Quaternion { - const x_vector: Vector = @splat(x); - return .{ .vector = @shuffle(Vector, self, x_vector, .{ ~@as(i32, 0), 1, 2, 3 }) }; + pub inline fn setVector(self: Quaternion, vector: Vector3) Quaternion { + return .{ + .vector = .{ + .vector = @shuffle(f32, self.vector.vector, vector.vector, .{ ~@as(i32, 0), ~@as(i32, 1), ~@as(i32, 2), 3 }), + }, + }; } - pub inline fn setY(self: Quaternion, y: f32) Quaternion { - const y_vector: Vector = @splat(y); - return .{ .vector = @shuffle(Vector, self, y_vector, .{ 0, ~@as(i32, 1), 2, 3 }) }; + pub inline fn setScalar(self: Quaternion, scalar: f32) Quaternion { + return .initVector4(self.vector.setW(scalar)); } - pub inline fn setZ(self: Quaternion, z: f32) Quaternion { - const z_vector: Vector = @splat(z); - return .{ .vector = @shuffle(Vector, self, z_vector, .{ 0, 1, ~@as(i32, 2), 3 }) }; - } - - pub inline fn setW(self: Quaternion, w: f32) Quaternion { - const w_vector: Vector = @splat(w); - return .{ .vector = @shuffle(Vector, self, w_vector, .{ 0, 1, 2, ~@as(i32, 3) }) }; - } + // --- COMPONENT-WISE --- pub inline fn add(self: Quaternion, other: Quaternion) Quaternion { - return .{ .vector = self.vector + other.vector }; + return .initVector4(Vector4.add(self.vector, other.vector)); } pub inline fn sub(self: Quaternion, other: Quaternion) Quaternion { - return .{ .vector = self.vector - other.vector }; + return .initVector4(Vector4.sub(self.vector, other.vector)); } - pub inline fn mul(self: Quaternion, other: Quaternion) Quaternion { - return .{ .vector = self.vector * other.vector }; + pub inline fn negate(self: Quaternion) Quaternion { + return .initVector4(Vector4.negate(self.vector)); } - pub inline fn div(self: Quaternion, other: Quaternion) Quaternion { - return .{ .vector = self.vector / other.vector }; + pub inline fn conjugate(self: Quaternion) Quaternion { + return .initVector4(Vector4.mul(self.vector, Vector4.init(-1, -1, -1, 1))); } pub inline fn mulScalar(self: Quaternion, scalar: f32) Quaternion { - const scalar_vector: Vector = @splat(scalar); - return .{ .vector = self.vector * scalar_vector }; + return .initVector4(Vector4.mulScalar(self.vector, scalar)); } pub inline fn divScalar(self: Quaternion, scalar: f32) Quaternion { - const scalar_vector: Vector = @splat(scalar); - return .{ .vector = self.vector / scalar_vector }; + return .initVector4(Vector4.divScalar(self.vector, scalar)); + } + + // --- OTHER --- + + pub inline fn len(self: Quaternion) f32 { + return self.vector.len(); + } + + pub inline fn lenSquared(self: Quaternion) f32 { + return self.vector.lenSquared(); + } + + pub inline fn normalize(self: Quaternion) Quaternion { + return .initVector4(Vector4.normalize(self.vector)); + } + + pub inline fn dot(self: Quaternion, other: Quaternion) f32 { + return Vector4.dot(self.vector, other.vector); } pub inline fn lerp(self: Quaternion, other: Quaternion, t: f32) Quaternion { - const s = 1.0 - t; - const t_vector: Vector = @splat(t); - const s_vector: Vector = @splat(s); - return .{ .vector = self * t_vector + other * s_vector }; + return .initVector4(Vector4.lerp(self.vector, other.vector, t)); + } + + pub inline fn mulQuaternion(self: Quaternion, other: Quaternion) Quaternion { + const x1, const y1, const z1, const w1 = self.vector.vector; + const x2, const y2, const z2, const w2 = other.vector.vector; + return .init( + w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2, + w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2, + w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2, + w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2, + ); } }; diff --git a/src/math/Vector2.zig b/src/math/Vector2.zig new file mode 100644 index 0000000..4d5d033 --- /dev/null +++ b/src/math/Vector2.zig @@ -0,0 +1,146 @@ +const Vector3 = @import("Vector3.zig").Vector3; +const Vector4 = @import("Vector3.zig").Vector4; + +pub const Vector2 = extern struct { + vector: Vector, + + pub const Vector = @Vector(2, f32); + pub const Mask = enum(i32) { x = 0, y = 1 }; + + pub const zero = Vector2.init(0, 0); + pub const one = Vector2.init(1, 1); + pub const unit_x = Vector2.init(1, 0); + pub const unit_y = Vector2.init(0, 1); + + // --- INIT --- + + pub inline fn init(x: f32, y: f32) Vector2 { + return .{ .vector = .{ x, y } }; + } + + pub inline fn initArray(array: [2]f32) Vector2 { + return .{ .vector = array }; + } + + // --- CONVERSION --- + + pub inline fn asArray(self: Vector2) [2]f32 { + return self.vector; + } + + pub inline fn asVector3(self: Vector2, z: f32) Vector3 { + const z_vector: @Vector(3, f32) = .{ undefined, undefined, z }; + return .{ .vector = @shuffle(f32, self.vector, z_vector, .{ 0, 1, ~@as(i32, -2) }) }; + } + + pub inline fn asVector4(self: Vector4, z: f32, w: f32) Vector4 { + const zw_vector: @Vector(4, f32) = .{ undefined, undefined, z, w }; + return .{ .vector = @shuffle(f32, self.vector, zw_vector, .{ 0, 1, ~@as(i32, -2), ~@as(i32, -3) }) }; + } + + // --- ACCESSORS --- + + pub inline fn getX(self: Vector2) f32 { + return self.vector[0]; + } + + pub inline fn getY(self: Vector2) f32 { + return self.vector[1]; + } + + pub inline fn setX(self: Vector2, x: f32) Vector2 { + const x_vector: Vector = @splat(x); + return .{ .vector = @shuffle(f32, self, x_vector, .{ ~@as(i32, 0), 1 }) }; + } + + pub inline fn setY(self: Vector2, y: f32) Vector2 { + const y_vector: Vector = @splat(y); + return .{ .vector = @shuffle(f32, self, y_vector, .{ 0, ~@as(i32, 1) }) }; + } + + // --- COMPONENT-WISE --- + + pub inline fn add(self: Vector2, other: Vector2) Vector2 { + return .{ .vector = self.vector + other.vector }; + } + + pub inline fn sub(self: Vector2, other: Vector2) Vector2 { + return .{ .vector = self.vector - other.vector }; + } + + pub inline fn mul(self: Vector2, other: Vector2) Vector2 { + return .{ .vector = self.vector * other.vector }; + } + + pub inline fn div(self: Vector2, other: Vector2) Vector2 { + return .{ .vector = self.vector / other.vector }; + } + + pub inline fn negate(self: Vector2) Vector2 { + return .{ .vector = -self.vector }; + } + + pub inline fn mulScalar(self: Vector2, scalar: f32) Vector2 { + const scalar_vector: Vector = @splat(scalar); + return .{ .vector = self.vector * scalar_vector }; + } + + pub inline fn divScalar(self: Vector2, scalar: f32) Vector2 { + const scalar_vector: Vector = @splat(scalar); + return .{ .vector = self.vector / scalar_vector }; + } + + // --- SWIZZLE --- + + pub inline fn swizzle2(self: Vector2, comptime mask: [2]Mask) Vector2 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) }; + } + + pub inline fn swizzle3(self: Vector2, comptime mask: [3]Mask) Vector3 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) }; + } + + pub inline fn swizzle4(self: Vector2, comptime mask: [4]Mask) Vector4 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([4]i32, @bitCast(mask))) }; + } + + // --- OTHER --- + + pub inline fn len(self: Vector2) f32 { + return @sqrt(@reduce(.Add, self.vector * self.vector)); + } + + pub inline fn lenSquared(self: Vector2) f32 { + return @reduce(.Add, self.vector * self.vector); + } + + pub inline fn normalize(self: Vector2) Vector2 { + return .{ .vector = self.vector / @sqrt(@reduce(.Add, self.vector * self.vector)) }; + } + + pub inline fn dot(self: Vector2, other: Vector2) f32 { + return @reduce(.Add, self.vector * other.vector); + } + + pub inline fn cross(self: Vector2, other: Vector2) f32 { + return self.getX() * other.getY() - self.getY() * other.getX(); + } + + pub inline fn lerp(self: Vector2, other: Vector2, t: f32) Vector2 { + const s = 1.0 - t; + const t_vector: Vector = @splat(t); + const s_vector: Vector = @splat(s); + return .{ .vector = self * t_vector + other * s_vector }; + } + + pub inline fn rotate(self: Vector2, angle_rad: f32) Vector2 { + const c = @cos(angle_rad); + const s = @sin(angle_rad); + return .{ + .vector = .{ + self.x * c - self.y * s, + self.x * s + self.x * c, + }, + }; + } +}; diff --git a/src/math/Vector3.zig b/src/math/Vector3.zig index b7d2706..05904b8 100644 --- a/src/math/Vector3.zig +++ b/src/math/Vector3.zig @@ -1,9 +1,12 @@ +const Quaternion = @import("Quaternion.zig").Quaternion; +const Vector2 = @import("Vector2.zig").Vector2; const Vector4 = @import("Vector4.zig").Vector4; pub const Vector3 = extern struct { vector: Vector, pub const Vector = @Vector(3, f32); + pub const Mask = enum(i32) { x = 0, y = 1, z = 2 }; pub const zero = Vector3.init(0, 0, 0); pub const one = Vector3.init(1, 1, 1); @@ -11,10 +14,33 @@ pub const Vector3 = extern struct { pub const unit_y = Vector3.init(0, 1, 0); pub const unit_z = Vector3.init(0, 0, 1); + // --- INIT --- + pub inline fn init(x: f32, y: f32, z: f32) Vector3 { return .{ .vector = .{ x, y, z } }; } + pub inline fn initArray(array: [3]f32) Vector3 { + return .{ .vector = array }; + } + + // --- CONVERSION --- + + pub inline fn asArray(self: Vector3) [3]f32 { + return self.vector; + } + + pub inline fn asVector2(self: Vector3) Vector2 { + return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1 }) }; + } + + pub inline fn asVector4(self: Vector3, w: f32) Vector4 { + const w_vector: @Vector(4, f32) = .{ undefined, undefined, undefined, w }; + return .{ .vector = @shuffle(f32, self.vector, w_vector, .{ 0, 1, 2, ~@as(i32, -3) }) }; + } + + // --- ACCESSORS --- + pub inline fn getX(self: Vector3) f32 { return self.vector[0]; } @@ -29,19 +55,21 @@ pub const Vector3 = extern struct { pub inline fn setX(self: Vector3, x: f32) Vector3 { const x_vector: Vector = @splat(x); - return .{ .vector = @shuffle(Vector, self, x_vector, .{ ~@as(i32, 0), 1, 2 }) }; + return .{ .vector = @shuffle(f32, self, x_vector, .{ ~@as(i32, 0), 1, 2 }) }; } pub inline fn setY(self: Vector3, y: f32) Vector3 { const y_vector: Vector = @splat(y); - return .{ .vector = @shuffle(Vector, self, y_vector, .{ 0, ~@as(i32, 1), 2 }) }; + return .{ .vector = @shuffle(f32, self, y_vector, .{ 0, ~@as(i32, 1), 2 }) }; } pub inline fn setZ(self: Vector3, z: f32) Vector3 { const z_vector: Vector = @splat(z); - return .{ .vector = @shuffle(Vector, self, z_vector, .{ 0, 1, ~@as(i32, 2) }) }; + return .{ .vector = @shuffle(f32, self, z_vector, .{ 0, 1, ~@as(i32, 2) }) }; } + // --- COMPONENT-WISE --- + pub inline fn add(self: Vector3, other: Vector3) Vector3 { return .{ .vector = self.vector + other.vector }; } @@ -58,6 +86,10 @@ pub const Vector3 = extern struct { return .{ .vector = self.vector / other.vector }; } + pub inline fn negate(self: Vector3) Vector3 { + return .{ .vector = -self.vector }; + } + pub inline fn mulScalar(self: Vector3, scalar: f32) Vector3 { const scalar_vector: Vector = @splat(scalar); return .{ .vector = self.vector * scalar_vector }; @@ -68,8 +100,46 @@ pub const Vector3 = extern struct { return .{ .vector = self.vector / scalar_vector }; } - pub inline fn negate(self: Vector3) Vector3 { - return .{ .vector = -self.vector }; + // --- SWIZZLE --- + + pub inline fn swizzle2(self: Vector3, comptime mask: [2]Mask) Vector2 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) }; + } + + pub inline fn swizzle3(self: Vector3, comptime mask: [3]Mask) Vector3 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) }; + } + + pub inline fn swizzle4(self: Vector3, comptime mask: [4]Mask) Vector4 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([4]i32, @bitCast(mask))) }; + } + + // --- OTHER --- + + pub inline fn len(self: Vector3) f32 { + return @sqrt(@reduce(.Add, self.vector * self.vector)); + } + + pub inline fn lenSquared(self: Vector3) f32 { + return @reduce(.Add, self.vector * self.vector); + } + + pub inline fn normalize(self: Vector3) Vector3 { + return .{ .vector = self.vector / @sqrt(@reduce(.Add, self.vector * self.vector)) }; + } + + pub inline fn dot(self: Vector3, other: Vector3) f32 { + return @reduce(.Add, self.vector * other.vector); + } + + pub inline fn cross(self: Vector3, other: Vector3) Vector3 { + return .{ + .vector = .{ + self.getY() * other.getZ() - self.getZ() * other.getY(), + self.getZ() * other.getX() - self.getX() * other.getZ(), + self.getX() * other.getY() - self.getY() * other.getX(), + }, + }; } pub inline fn lerp(self: Vector3, other: Vector3, t: f32) Vector3 { @@ -79,15 +149,19 @@ pub const Vector3 = extern struct { return .{ .vector = self * t_vector + other * s_vector }; } - pub inline fn swizzle3(self: Vector3, comptime mask: @Vector(3, i32)) Vector3 { - return .{ .vector = @shuffle(Vector, self, undefined, mask) }; - } + pub inline fn rotate(self: Vector3, quaternion: Quaternion) Vector2 { + const quaternion_scalar = quaternion.getScalar(); + const quaternion_vector = quaternion.getVector(); - pub inline fn swizzle4(self: Vector3, comptime mask: @Vector(4, i32)) Vector4 { - return .{ .vector = @shuffle(Vector4.Vector, self, undefined, mask) }; - } - - pub inline fn asArray(self: Vector3) [3]f32 { - return self.vector; + return Vector3.add( + self, + Vector3.cross( + Vector3.add(quaternion_vector, quaternion_vector), + Vector3.add( + Vector3.cross(quaternion_vector, self), + Vector3.mulScalar(self, quaternion_scalar), + ), + ), + ); } }; diff --git a/src/math/Vector4.zig b/src/math/Vector4.zig index c26f751..9ecd3c3 100644 --- a/src/math/Vector4.zig +++ b/src/math/Vector4.zig @@ -1,9 +1,11 @@ +const Vector2 = @import("Vector2.zig").Vector2; const Vector3 = @import("Vector3.zig").Vector3; pub const Vector4 = extern struct { vector: Vector, pub const Vector = @Vector(4, f32); + pub const Mask = enum(i32) { x = 0, y = 1, z = 2, w = 3 }; pub const zero = Vector4.init(0, 0, 0, 0); pub const one = Vector4.init(1, 1, 1, 1); @@ -12,10 +14,32 @@ pub const Vector4 = extern struct { pub const unit_z = Vector4.init(0, 0, 1, 0); pub const unit_w = Vector4.init(0, 0, 0, 1); + // --- INIT --- + pub inline fn init(x: f32, y: f32, z: f32, w: f32) Vector4 { return .{ .vector = .{ x, y, z, w } }; } + pub inline fn initArray(array: [4]f32) Vector4 { + return .{ .vector = array }; + } + + // --- CONVERSION --- + + pub inline fn asArray(self: Vector4) [4]f32 { + return self.vector; + } + + pub inline fn asVector2(self: Vector4) Vector2 { + return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1 }) }; + } + + pub inline fn asVector3(self: Vector4) Vector3 { + return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1, 2 }) }; + } + + // --- ACCESSORS --- + pub inline fn getX(self: Vector4) f32 { return self.vector[0]; } @@ -34,24 +58,26 @@ pub const Vector4 = extern struct { pub inline fn setX(self: Vector4, x: f32) Vector4 { const x_vector: Vector = @splat(x); - return .{ .vector = @shuffle(Vector, self, x_vector, .{ ~@as(i32, 0), 1, 2, 3 }) }; + return .{ .vector = @shuffle(f32, self, x_vector, .{ ~@as(i32, 0), 1, 2, 3 }) }; } pub inline fn setY(self: Vector4, y: f32) Vector4 { const y_vector: Vector = @splat(y); - return .{ .vector = @shuffle(Vector, self, y_vector, .{ 0, ~@as(i32, 1), 2, 3 }) }; + return .{ .vector = @shuffle(f32, self, y_vector, .{ 0, ~@as(i32, 1), 2, 3 }) }; } pub inline fn setZ(self: Vector4, z: f32) Vector4 { const z_vector: Vector = @splat(z); - return .{ .vector = @shuffle(Vector, self, z_vector, .{ 0, 1, ~@as(i32, 2), 3 }) }; + return .{ .vector = @shuffle(f32, self, z_vector, .{ 0, 1, ~@as(i32, 2), 3 }) }; } pub inline fn setW(self: Vector4, w: f32) Vector4 { const w_vector: Vector = @splat(w); - return .{ .vector = @shuffle(Vector, self, w_vector, .{ 0, 1, 2, ~@as(i32, 3) }) }; + return .{ .vector = @shuffle(f32, self, w_vector, .{ 0, 1, 2, ~@as(i32, 3) }) }; } + // --- COMPONENT-WISE --- + pub inline fn add(self: Vector4, other: Vector4) Vector4 { return .{ .vector = self.vector + other.vector }; } @@ -68,6 +94,10 @@ pub const Vector4 = extern struct { return .{ .vector = self.vector / other.vector }; } + pub inline fn negate(self: Vector4) Vector4 { + return .{ .vector = -self.vector }; + } + pub inline fn mulScalar(self: Vector4, scalar: f32) Vector4 { const scalar_vector: Vector = @splat(scalar); return .{ .vector = self.vector * scalar_vector }; @@ -78,8 +108,36 @@ pub const Vector4 = extern struct { return .{ .vector = self.vector / scalar_vector }; } - pub inline fn negate(self: Vector4) Vector4 { - return .{ .vector = -self.vector }; + // --- SWIZZLE --- + + pub inline fn swizzle2(self: Vector4, comptime mask: [2]Mask) Vector2 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) }; + } + + pub inline fn swizzle3(self: Vector4, comptime mask: [3]Mask) Vector3 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) }; + } + + pub inline fn swizzle4(self: Vector4, comptime mask: [4]Mask) Vector4 { + return .{ .vector = @shuffle(f32, self.vector, undefined, @as([4]i32, @bitCast(mask))) }; + } + + // --- OTHER --- + + pub inline fn len(self: Vector4) f32 { + return @sqrt(@reduce(.Add, self.vector * self.vector)); + } + + pub inline fn lenSquared(self: Vector4) f32 { + return @reduce(.Add, self.vector * self.vector); + } + + pub inline fn normalize(self: Vector4) Vector4 { + return .{ .vector = self.vector / @sqrt(@reduce(.Add, self.vector * self.vector)) }; + } + + pub inline fn dot(self: Vector4, other: Vector4) f32 { + return @reduce(.Add, self.vector * other.vector); } pub inline fn lerp(self: Vector4, other: Vector4, t: f32) Vector4 { @@ -88,20 +146,4 @@ pub const Vector4 = extern struct { const s_vector: Vector = @splat(s); return .{ .vector = self * t_vector + other * s_vector }; } - - pub inline fn asVector3(self: Vector4) Vector3 { - return .{ .vector = @shuffle(Vector3.Vector, self.vector, undefined, .{ 0, 1, 2 }) }; - } - - pub inline fn swizzle3(self: Vector4, comptime mask: @Vector(3, i32)) Vector3 { - return .{ .vector = @shuffle(Vector3.Vector, self.vector, undefined, mask) }; - } - - pub inline fn swizzle4(self: Vector4, comptime mask: @Vector(4, i32)) Vector4 { - return .{ .vector = @shuffle(Vector, self.vector, undefined, mask) }; - } - - pub inline fn asArray(self: Vector4) [4]f32 { - return self.vector; - } };