math: remove usingnamespace in favour of mixins (#1231)
This commit is contained in:
parent
42d2a57611
commit
af7ac96a0e
5 changed files with 828 additions and 606 deletions
|
|
@ -50,34 +50,34 @@ const ray = @import("ray.zig");
|
||||||
pub const collision = @import("collision.zig");
|
pub const collision = @import("collision.zig");
|
||||||
|
|
||||||
/// Standard f32 precision types
|
/// Standard f32 precision types
|
||||||
pub const Vec2 = vec.Vec(2, f32);
|
pub const Vec2 = vec.Vec2(f32);
|
||||||
pub const Vec3 = vec.Vec(3, f32);
|
pub const Vec3 = vec.Vec3(f32);
|
||||||
pub const Vec4 = vec.Vec(4, f32);
|
pub const Vec4 = vec.Vec4(f32);
|
||||||
pub const Quat = q.Quat(f32);
|
pub const Quat = q.Quat(f32);
|
||||||
pub const Mat2x2 = mat.Mat(2, 2, Vec2);
|
pub const Mat2x2 = mat.Mat2x2(f32);
|
||||||
pub const Mat3x3 = mat.Mat(3, 3, Vec3);
|
pub const Mat3x3 = mat.Mat3x3(f32);
|
||||||
pub const Mat4x4 = mat.Mat(4, 4, Vec4);
|
pub const Mat4x4 = mat.Mat4x4(f32);
|
||||||
pub const Ray = ray.Ray(Vec3);
|
pub const Ray = ray.Ray3(f32);
|
||||||
|
|
||||||
/// Half-precision f16 types
|
/// Half-precision f16 types
|
||||||
pub const Vec2h = vec.Vec(2, f16);
|
pub const Vec2h = vec.Vec2(f16);
|
||||||
pub const Vec3h = vec.Vec(3, f16);
|
pub const Vec3h = vec.Vec3(f16);
|
||||||
pub const Vec4h = vec.Vec(4, f16);
|
pub const Vec4h = vec.Vec4(f16);
|
||||||
pub const Quath = q.Quat(f16);
|
pub const Quath = q.Quat(f16);
|
||||||
pub const Mat2x2h = mat.Mat(2, 2, Vec2h);
|
pub const Mat2x2h = mat.Mat2x2(f16);
|
||||||
pub const Mat3x3h = mat.Mat(3, 3, Vec3h);
|
pub const Mat3x3h = mat.Mat3x3(f16);
|
||||||
pub const Mat4x4h = mat.Mat(4, 4, Vec4h);
|
pub const Mat4x4h = mat.Mat4x4(f16);
|
||||||
pub const Rayh = ray.Ray(Vec3h);
|
pub const Rayh = ray.Ray3(f16);
|
||||||
|
|
||||||
/// Double-precision f64 types
|
/// Double-precision f64 types
|
||||||
pub const Vec2d = vec.Vec(2, f64);
|
pub const Vec2d = vec.Vec2(f64);
|
||||||
pub const Vec3d = vec.Vec(3, f64);
|
pub const Vec3d = vec.Vec3(f64);
|
||||||
pub const Vec4d = vec.Vec(4, f64);
|
pub const Vec4d = vec.Vec4(f64);
|
||||||
pub const Quatd = q.Quat(f64);
|
pub const Quatd = q.Quat(f64);
|
||||||
pub const Mat2x2d = mat.Mat(2, 2, Vec2d);
|
pub const Mat2x2d = mat.Mat2x2(f64);
|
||||||
pub const Mat3x3d = mat.Mat(3, 3, Vec3d);
|
pub const Mat3x3d = mat.Mat3x3(f64);
|
||||||
pub const Mat4x4d = mat.Mat(4, 4, Vec4d);
|
pub const Mat4x4d = mat.Mat4x4(f64);
|
||||||
pub const Rayd = ray.Ray(Vec3d);
|
pub const Rayd = ray.Ray3(f64);
|
||||||
|
|
||||||
/// Standard f32 precision initializers
|
/// Standard f32 precision initializers
|
||||||
pub const vec2 = Vec2.init;
|
pub const vec2 = Vec2.init;
|
||||||
|
|
|
||||||
745
src/math/mat.zig
745
src/math/mat.zig
|
|
@ -3,10 +3,8 @@ const testing = mach.testing;
|
||||||
const math = mach.math;
|
const math = mach.math;
|
||||||
const vec = @import("vec.zig");
|
const vec = @import("vec.zig");
|
||||||
|
|
||||||
pub fn Mat(
|
pub fn Mat2x2(
|
||||||
comptime n_cols: usize,
|
comptime Scalar: type,
|
||||||
comptime n_rows: usize,
|
|
||||||
comptime Vector: type,
|
|
||||||
) type {
|
) type {
|
||||||
return extern struct {
|
return extern struct {
|
||||||
/// The column vectors of the matrix.
|
/// The column vectors of the matrix.
|
||||||
|
|
@ -28,367 +26,468 @@ pub fn Mat(
|
||||||
v: [cols]Vec,
|
v: [cols]Vec,
|
||||||
|
|
||||||
/// The number of columns, e.g. Mat3x4.cols == 3
|
/// The number of columns, e.g. Mat3x4.cols == 3
|
||||||
pub const cols = n_cols;
|
pub const cols = 2;
|
||||||
|
|
||||||
/// The number of rows, e.g. Mat3x4.rows == 4
|
/// The number of rows, e.g. Mat3x4.rows == 4
|
||||||
pub const rows = n_rows;
|
pub const rows = 2;
|
||||||
|
|
||||||
/// The scalar type of this matrix, e.g. Mat3x3.T == f32
|
/// The scalar type of this matrix, e.g. Mat3x3.T == f32
|
||||||
pub const T = Vector.T;
|
pub const T = Scalar;
|
||||||
|
|
||||||
/// The underlying Vec type, e.g. Mat3x3.Vec == Vec3
|
/// The underlying Vec type, e.g. Mat3x3.Vec == Vec3
|
||||||
pub const Vec = Vector;
|
pub const Vec = vec.Vec2(Scalar);
|
||||||
|
|
||||||
/// The Vec type corresponding to the number of rows, e.g. Mat3x3.RowVec == Vec3
|
/// The Vec type corresponding to the number of rows, e.g. Mat3x3.RowVec == Vec3
|
||||||
pub const RowVec = vec.Vec(rows, T);
|
pub const RowVec = Vec;
|
||||||
|
|
||||||
/// The Vec type corresponding to the numebr of cols, e.g. Mat3x4.ColVec = Vec4
|
/// The Vec type corresponding to the numebr of cols, e.g. Mat3x4.ColVec = Vec4
|
||||||
pub const ColVec = vec.Vec(cols, T);
|
pub const ColVec = Vec;
|
||||||
|
|
||||||
const Matrix = @This();
|
const Matrix = @This();
|
||||||
|
|
||||||
|
const Shared = MatShared(RowVec, ColVec, Matrix);
|
||||||
|
|
||||||
/// Identity matrix
|
/// Identity matrix
|
||||||
pub const ident = switch (Matrix) {
|
pub const ident = Matrix.init(
|
||||||
inline math.Mat2x2, math.Mat2x2h, math.Mat2x2d => Matrix.init(
|
&RowVec.init(1, 0),
|
||||||
&RowVec.init(1, 0),
|
&RowVec.init(0, 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Constructs a 2x2 matrix with the given rows. For example to write a translation
|
||||||
|
/// matrix like in the left part of this equation:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// |1 tx| |x | |x+y*tx|
|
||||||
|
/// |0 ty| |y=1| = |ty |
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You would write it with the same visual layout:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// const m = Mat2x2.init(
|
||||||
|
/// vec3(1, tx),
|
||||||
|
/// vec3(0, ty),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
||||||
|
pub inline fn init(r0: *const RowVec, r1: *const RowVec) Matrix {
|
||||||
|
return .{ .v = [_]Vec{
|
||||||
|
Vec.init(r0.x(), r1.x()),
|
||||||
|
Vec.init(r0.y(), r1.y()),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the row `i` of the matrix.
|
||||||
|
pub inline fn row(m: *const Matrix, i: usize) RowVec {
|
||||||
|
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
||||||
|
// return RowVec.init(m.v[0].v[i], m.v[1].v[i]);
|
||||||
|
return .{ .v = .{ m.v[0].v[i], m.v[1].v[i] } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the column `i` of the matrix.
|
||||||
|
pub inline fn col(m: *const Matrix, i: usize) RowVec {
|
||||||
|
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
||||||
|
// return RowVec.init(m.v[i].v[0], m.v[i].v[1]);
|
||||||
|
return .{ .v = .{ m.v[i].v[0], m.v[i].v[1] } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transposes the matrix.
|
||||||
|
pub inline fn transpose(m: *const Matrix) Matrix {
|
||||||
|
return .{ .v = [_]Vec{
|
||||||
|
Vec.init(m.v[0].v[0], m.v[1].v[0]),
|
||||||
|
Vec.init(m.v[0].v[1], m.v[1].v[1]),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a 1D matrix which scales each dimension by the given scalar.
|
||||||
|
pub inline fn scaleScalar(t: Vec.T) Matrix {
|
||||||
|
return init(
|
||||||
|
&RowVec.init(t, 0),
|
||||||
&RowVec.init(0, 1),
|
&RowVec.init(0, 1),
|
||||||
),
|
);
|
||||||
inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => Matrix.init(
|
}
|
||||||
&RowVec.init(1, 0, 0),
|
|
||||||
&RowVec.init(0, 1, 0),
|
/// Constructs a 1D matrix which translates coordinates by the given scalar.
|
||||||
|
pub inline fn translateScalar(t: Vec.T) Matrix {
|
||||||
|
return init(
|
||||||
|
&RowVec.init(1, t),
|
||||||
|
&RowVec.init(0, 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const mul = Shared.mul;
|
||||||
|
pub const mulVec = Shared.mulVec;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Mat3x3(
|
||||||
|
comptime Scalar: type,
|
||||||
|
) type {
|
||||||
|
return extern struct {
|
||||||
|
/// The column vectors of the matrix.
|
||||||
|
///
|
||||||
|
/// Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
||||||
|
/// The translation vector is stored in contiguous memory elements 12, 13, 14:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// [4]Vec4{
|
||||||
|
/// vec4( 1, 0, 0, 0),
|
||||||
|
/// vec4( 0, 1, 0, 0),
|
||||||
|
/// vec4( 0, 0, 1, 0),
|
||||||
|
/// vec4(tx, ty, tz, tw),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use the init() constructor to write code which visually matches the same layout as you'd
|
||||||
|
/// see used in scientific / maths communities.
|
||||||
|
v: [cols]Vec,
|
||||||
|
|
||||||
|
/// The number of columns, e.g. Mat3x4.cols == 3
|
||||||
|
pub const cols = 3;
|
||||||
|
|
||||||
|
/// The number of rows, e.g. Mat3x4.rows == 4
|
||||||
|
pub const rows = 3;
|
||||||
|
|
||||||
|
/// The scalar type of this matrix, e.g. Mat3x3.T == f32
|
||||||
|
pub const T = Scalar;
|
||||||
|
|
||||||
|
/// The underlying Vec type, e.g. Mat3x3.Vec == Vec3
|
||||||
|
pub const Vec = vec.Vec3(Scalar);
|
||||||
|
|
||||||
|
/// The Vec type corresponding to the number of rows, e.g. Mat3x3.RowVec == Vec3
|
||||||
|
pub const RowVec = Vec;
|
||||||
|
|
||||||
|
/// The Vec type corresponding to the numebr of cols, e.g. Mat3x4.ColVec = Vec4
|
||||||
|
pub const ColVec = Vec;
|
||||||
|
|
||||||
|
const Matrix = @This();
|
||||||
|
|
||||||
|
const Shared = MatShared(RowVec, ColVec, Matrix);
|
||||||
|
|
||||||
|
/// Identity matrix
|
||||||
|
pub const ident = Matrix.init(
|
||||||
|
&RowVec.init(1, 0, 0),
|
||||||
|
&RowVec.init(0, 1, 0),
|
||||||
|
&RowVec.init(0, 0, 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Constructs a 3x3 matrix with the given rows. For example to write a translation
|
||||||
|
/// matrix like in the left part of this equation:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// |1 0 tx| |x | |x+z*tx|
|
||||||
|
/// |0 1 ty| |y | = |y+z*ty|
|
||||||
|
/// |0 0 tz| |z=1| |tz |
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You would write it with the same visual layout:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// const m = Mat3x3.init(
|
||||||
|
/// vec3(1, 0, tx),
|
||||||
|
/// vec3(0, 1, ty),
|
||||||
|
/// vec3(0, 0, tz),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
||||||
|
pub inline fn init(r0: *const RowVec, r1: *const RowVec, r2: *const RowVec) Matrix {
|
||||||
|
return .{ .v = [_]Vec{
|
||||||
|
Vec.init(r0.x(), r1.x(), r2.x()),
|
||||||
|
Vec.init(r0.y(), r1.y(), r2.y()),
|
||||||
|
Vec.init(r0.z(), r1.z(), r2.z()),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the row `i` of the matrix.
|
||||||
|
pub inline fn row(m: *const Matrix, i: usize) RowVec {
|
||||||
|
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
||||||
|
// return RowVec.init(m.v[0].v[i], m.v[1].v[i], m.v[2].v[i]);
|
||||||
|
return .{ .v = .{ m.v[0].v[i], m.v[1].v[i], m.v[2].v[i] } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the column `i` of the matrix.
|
||||||
|
pub inline fn col(m: *const Matrix, i: usize) RowVec {
|
||||||
|
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
||||||
|
// return RowVec.init(m.v[i].v[0], m.v[i].v[1], m.v[i].v[2]);
|
||||||
|
return .{ .v = .{ m.v[i].v[0], m.v[i].v[1], m.v[i].v[2] } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transposes the matrix.
|
||||||
|
pub inline fn transpose(m: *const Matrix) Matrix {
|
||||||
|
return .{ .v = [_]Vec{
|
||||||
|
Vec.init(m.v[0].v[0], m.v[1].v[0], m.v[2].v[0]),
|
||||||
|
Vec.init(m.v[0].v[1], m.v[1].v[1], m.v[2].v[1]),
|
||||||
|
Vec.init(m.v[0].v[2], m.v[1].v[2], m.v[2].v[2]),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a 2D matrix which scales each dimension by the given vector.
|
||||||
|
pub inline fn scale(s: math.Vec2) Matrix {
|
||||||
|
return init(
|
||||||
|
&RowVec.init(s.x(), 0, 0),
|
||||||
|
&RowVec.init(0, s.y(), 0),
|
||||||
&RowVec.init(0, 0, 1),
|
&RowVec.init(0, 0, 1),
|
||||||
),
|
);
|
||||||
inline math.Mat4x4, math.Mat4x4h, math.Mat4x4d => Matrix.init(
|
}
|
||||||
&Vec.init(1, 0, 0, 0),
|
|
||||||
&Vec.init(0, 1, 0, 0),
|
|
||||||
&Vec.init(0, 0, 1, 0),
|
|
||||||
&Vec.init(0, 0, 0, 1),
|
|
||||||
),
|
|
||||||
else => @compileError("Expected Mat3x3, Mat4x4 found '" ++ @typeName(Matrix) ++ "'"),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub usingnamespace switch (Matrix) {
|
/// Constructs a 2D matrix which scales each dimension by the given scalar.
|
||||||
inline math.Mat2x2, math.Mat2x2h, math.Mat2x2d => struct {
|
pub inline fn scaleScalar(t: Vec.T) Matrix {
|
||||||
/// Constructs a 2x2 matrix with the given rows. For example to write a translation
|
return scale(math.Vec2.splat(t));
|
||||||
/// matrix like in the left part of this equation:
|
}
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// |1 tx| |x | |x+y*tx|
|
|
||||||
/// |0 ty| |y=1| = |ty |
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You would write it with the same visual layout:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// const m = Mat2x2.init(
|
|
||||||
/// vec3(1, tx),
|
|
||||||
/// vec3(0, ty),
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
|
||||||
pub inline fn init(r0: *const RowVec, r1: *const RowVec) Matrix {
|
|
||||||
return .{ .v = [_]Vec{
|
|
||||||
Vec.init(r0.x(), r1.x()),
|
|
||||||
Vec.init(r0.y(), r1.y()),
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the row `i` of the matrix.
|
/// Constructs a 2D matrix which translates coordinates by the given vector.
|
||||||
pub inline fn row(m: *const Matrix, i: usize) RowVec {
|
pub inline fn translate(t: math.Vec2) Matrix {
|
||||||
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
return init(
|
||||||
// return RowVec.init(m.v[0].v[i], m.v[1].v[i]);
|
&RowVec.init(1, 0, t.x()),
|
||||||
return .{ .v = .{ m.v[0].v[i], m.v[1].v[i] } };
|
&RowVec.init(0, 1, t.y()),
|
||||||
}
|
&RowVec.init(0, 0, 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the column `i` of the matrix.
|
/// Constructs a 2D matrix which translates coordinates by the given scalar.
|
||||||
pub inline fn col(m: *const Matrix, i: usize) RowVec {
|
pub inline fn translateScalar(t: Vec.T) Matrix {
|
||||||
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
return translate(math.Vec2.splat(t));
|
||||||
// return RowVec.init(m.v[i].v[0], m.v[i].v[1]);
|
}
|
||||||
return .{ .v = .{ m.v[i].v[0], m.v[i].v[1] } };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transposes the matrix.
|
/// Returns the translation component of the matrix.
|
||||||
pub inline fn transpose(m: *const Matrix) Matrix {
|
pub inline fn translation(t: Matrix) math.Vec2 {
|
||||||
return .{ .v = [_]Vec{
|
return math.Vec2.init(t.v[2].x(), t.v[2].y());
|
||||||
Vec.init(m.v[0].v[0], m.v[1].v[0]),
|
}
|
||||||
Vec.init(m.v[0].v[1], m.v[1].v[1]),
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 1D matrix which scales each dimension by the given scalar.
|
pub const mul = Shared.mul;
|
||||||
pub inline fn scaleScalar(t: Vec.T) Matrix {
|
pub const mulVec = Shared.mulVec;
|
||||||
return init(
|
};
|
||||||
&RowVec.init(t, 0),
|
}
|
||||||
&RowVec.init(0, 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 1D matrix which translates coordinates by the given scalar.
|
pub fn Mat4x4(
|
||||||
pub inline fn translateScalar(t: Vec.T) Matrix {
|
comptime Scalar: type,
|
||||||
return init(
|
) type {
|
||||||
&RowVec.init(1, t),
|
return extern struct {
|
||||||
&RowVec.init(0, 1),
|
/// The column vectors of the matrix.
|
||||||
);
|
///
|
||||||
}
|
/// Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
||||||
},
|
/// The translation vector is stored in contiguous memory elements 12, 13, 14:
|
||||||
inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => struct {
|
///
|
||||||
/// Constructs a 3x3 matrix with the given rows. For example to write a translation
|
/// ```
|
||||||
/// matrix like in the left part of this equation:
|
/// [4]Vec4{
|
||||||
///
|
/// vec4( 1, 0, 0, 0),
|
||||||
/// ```
|
/// vec4( 0, 1, 0, 0),
|
||||||
/// |1 0 tx| |x | |x+z*tx|
|
/// vec4( 0, 0, 1, 0),
|
||||||
/// |0 1 ty| |y | = |y+z*ty|
|
/// vec4(tx, ty, tz, tw),
|
||||||
/// |0 0 tz| |z=1| |tz |
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// You would write it with the same visual layout:
|
/// Use the init() constructor to write code which visually matches the same layout as you'd
|
||||||
///
|
/// see used in scientific / maths communities.
|
||||||
/// ```
|
v: [cols]Vec,
|
||||||
/// const m = Mat3x3.init(
|
|
||||||
/// vec3(1, 0, tx),
|
|
||||||
/// vec3(0, 1, ty),
|
|
||||||
/// vec3(0, 0, tz),
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
|
||||||
pub inline fn init(r0: *const RowVec, r1: *const RowVec, r2: *const RowVec) Matrix {
|
|
||||||
return .{ .v = [_]Vec{
|
|
||||||
Vec.init(r0.x(), r1.x(), r2.x()),
|
|
||||||
Vec.init(r0.y(), r1.y(), r2.y()),
|
|
||||||
Vec.init(r0.z(), r1.z(), r2.z()),
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the row `i` of the matrix.
|
/// The number of columns, e.g. Mat3x4.cols == 3
|
||||||
pub inline fn row(m: *const Matrix, i: usize) RowVec {
|
pub const cols = 4;
|
||||||
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
|
||||||
// return RowVec.init(m.v[0].v[i], m.v[1].v[i], m.v[2].v[i]);
|
|
||||||
return .{ .v = .{ m.v[0].v[i], m.v[1].v[i], m.v[2].v[i] } };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the column `i` of the matrix.
|
/// The number of rows, e.g. Mat3x4.rows == 4
|
||||||
pub inline fn col(m: *const Matrix, i: usize) RowVec {
|
pub const rows = 4;
|
||||||
// Note: we inline RowVec.init manually here as it is faster in debug builds.
|
|
||||||
// return RowVec.init(m.v[i].v[0], m.v[i].v[1], m.v[i].v[2]);
|
|
||||||
return .{ .v = .{ m.v[i].v[0], m.v[i].v[1], m.v[i].v[2] } };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transposes the matrix.
|
/// The scalar type of this matrix, e.g. Mat3x3.T == f32
|
||||||
pub inline fn transpose(m: *const Matrix) Matrix {
|
pub const T = Scalar;
|
||||||
return .{ .v = [_]Vec{
|
|
||||||
Vec.init(m.v[0].v[0], m.v[1].v[0], m.v[2].v[0]),
|
|
||||||
Vec.init(m.v[0].v[1], m.v[1].v[1], m.v[2].v[1]),
|
|
||||||
Vec.init(m.v[0].v[2], m.v[1].v[2], m.v[2].v[2]),
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 2D matrix which scales each dimension by the given vector.
|
/// The underlying Vec type, e.g. Mat3x3.Vec == Vec3
|
||||||
pub inline fn scale(s: math.Vec2) Matrix {
|
pub const Vec = vec.Vec4(Scalar);
|
||||||
return init(
|
|
||||||
&RowVec.init(s.x(), 0, 0),
|
|
||||||
&RowVec.init(0, s.y(), 0),
|
|
||||||
&RowVec.init(0, 0, 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 2D matrix which scales each dimension by the given scalar.
|
/// The Vec type corresponding to the number of rows, e.g. Mat3x3.RowVec == Vec3
|
||||||
pub inline fn scaleScalar(t: Vec.T) Matrix {
|
pub const RowVec = Vec;
|
||||||
return scale(math.Vec2.splat(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 2D matrix which translates coordinates by the given vector.
|
/// The Vec type corresponding to the numebr of cols, e.g. Mat3x4.ColVec = Vec4
|
||||||
pub inline fn translate(t: math.Vec2) Matrix {
|
pub const ColVec = Vec;
|
||||||
return init(
|
|
||||||
&RowVec.init(1, 0, t.x()),
|
|
||||||
&RowVec.init(0, 1, t.y()),
|
|
||||||
&RowVec.init(0, 0, 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 2D matrix which translates coordinates by the given scalar.
|
const Matrix = @This();
|
||||||
pub inline fn translateScalar(t: Vec.T) Matrix {
|
|
||||||
return translate(math.Vec2.splat(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the translation component of the matrix.
|
const Shared = MatShared(RowVec, ColVec, Matrix);
|
||||||
pub inline fn translation(t: Matrix) math.Vec2 {
|
|
||||||
return math.Vec2.init(t.v[2].x(), t.v[2].y());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inline math.Mat4x4, math.Mat4x4h, math.Mat4x4d => struct {
|
|
||||||
/// Constructs a 4x4 matrix with the given rows. For example to write a translation
|
|
||||||
/// matrix like in the left part of this equation:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// |1 0 0 tx| |x | |x+w*tx|
|
|
||||||
/// |0 1 0 ty| |y | = |y+w*ty|
|
|
||||||
/// |0 0 1 tz| |z | |z+w*tz|
|
|
||||||
/// |0 0 0 tw| |w=1| |tw |
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You would write it with the same visual layout:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// const m = Mat4x4.init(
|
|
||||||
/// &vec4(1, 0, 0, tx),
|
|
||||||
/// &vec4(0, 1, 0, ty),
|
|
||||||
/// &vec4(0, 0, 1, tz),
|
|
||||||
/// &vec4(0, 0, 0, tw),
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
|
||||||
pub inline fn init(r0: *const RowVec, r1: *const RowVec, r2: *const RowVec, r3: *const RowVec) Matrix {
|
|
||||||
return .{ .v = [_]Vec{
|
|
||||||
Vec.init(r0.x(), r1.x(), r2.x(), r3.x()),
|
|
||||||
Vec.init(r0.y(), r1.y(), r2.y(), r3.y()),
|
|
||||||
Vec.init(r0.z(), r1.z(), r2.z(), r3.z()),
|
|
||||||
Vec.init(r0.w(), r1.w(), r2.w(), r3.w()),
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the row `i` of the matrix.
|
/// Identity matrix
|
||||||
pub inline fn row(m: *const Matrix, i: usize) RowVec {
|
pub const ident = Matrix.init(
|
||||||
return RowVec{ .v = RowVec.Vector{ m.v[0].v[i], m.v[1].v[i], m.v[2].v[i], m.v[3].v[i] } };
|
&Vec.init(1, 0, 0, 0),
|
||||||
}
|
&Vec.init(0, 1, 0, 0),
|
||||||
|
&Vec.init(0, 0, 1, 0),
|
||||||
|
&Vec.init(0, 0, 0, 1),
|
||||||
|
);
|
||||||
|
|
||||||
/// Returns the column `i` of the matrix.
|
/// Constructs a 4x4 matrix with the given rows. For example to write a translation
|
||||||
pub inline fn col(m: *const Matrix, i: usize) RowVec {
|
/// matrix like in the left part of this equation:
|
||||||
return RowVec{ .v = RowVec.Vector{ m.v[i].v[0], m.v[i].v[1], m.v[i].v[2], m.v[i].v[3] } };
|
///
|
||||||
}
|
/// ```
|
||||||
|
/// |1 0 0 tx| |x | |x+w*tx|
|
||||||
|
/// |0 1 0 ty| |y | = |y+w*ty|
|
||||||
|
/// |0 0 1 tz| |z | |z+w*tz|
|
||||||
|
/// |0 0 0 tw| |w=1| |tw |
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You would write it with the same visual layout:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// const m = Mat4x4.init(
|
||||||
|
/// &vec4(1, 0, 0, tx),
|
||||||
|
/// &vec4(0, 1, 0, ty),
|
||||||
|
/// &vec4(0, 0, 1, tz),
|
||||||
|
/// &vec4(0, 0, 0, tw),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/).
|
||||||
|
pub inline fn init(r0: *const RowVec, r1: *const RowVec, r2: *const RowVec, r3: *const RowVec) Matrix {
|
||||||
|
return .{ .v = [_]Vec{
|
||||||
|
Vec.init(r0.x(), r1.x(), r2.x(), r3.x()),
|
||||||
|
Vec.init(r0.y(), r1.y(), r2.y(), r3.y()),
|
||||||
|
Vec.init(r0.z(), r1.z(), r2.z(), r3.z()),
|
||||||
|
Vec.init(r0.w(), r1.w(), r2.w(), r3.w()),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
/// Transposes the matrix.
|
/// Returns the row `i` of the matrix.
|
||||||
pub inline fn transpose(m: *const Matrix) Matrix {
|
pub inline fn row(m: *const Matrix, i: usize) RowVec {
|
||||||
return .{ .v = [_]Vec{
|
return RowVec{ .v = RowVec.Vector{ m.v[0].v[i], m.v[1].v[i], m.v[2].v[i], m.v[3].v[i] } };
|
||||||
Vec.init(m.v[0].v[0], m.v[1].v[0], m.v[2].v[0], m.v[3].v[0]),
|
}
|
||||||
Vec.init(m.v[0].v[1], m.v[1].v[1], m.v[2].v[1], m.v[3].v[1]),
|
|
||||||
Vec.init(m.v[0].v[2], m.v[1].v[2], m.v[2].v[2], m.v[3].v[2]),
|
|
||||||
Vec.init(m.v[0].v[3], m.v[1].v[3], m.v[2].v[3], m.v[3].v[3]),
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 3D matrix which scales each dimension by the given vector.
|
/// Returns the column `i` of the matrix.
|
||||||
pub inline fn scale(s: math.Vec3) Matrix {
|
pub inline fn col(m: *const Matrix, i: usize) RowVec {
|
||||||
return init(
|
return RowVec{ .v = RowVec.Vector{ m.v[i].v[0], m.v[i].v[1], m.v[i].v[2], m.v[i].v[3] } };
|
||||||
&RowVec.init(s.x(), 0, 0, 0),
|
}
|
||||||
&RowVec.init(0, s.y(), 0, 0),
|
|
||||||
&RowVec.init(0, 0, s.z(), 0),
|
|
||||||
&RowVec.init(0, 0, 0, 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 3D matrix which scales each dimension by the given scalar.
|
/// Transposes the matrix.
|
||||||
pub inline fn scaleScalar(s: Vec.T) Matrix {
|
pub inline fn transpose(m: *const Matrix) Matrix {
|
||||||
return scale(math.Vec3.splat(s));
|
return .{ .v = [_]Vec{
|
||||||
}
|
Vec.init(m.v[0].v[0], m.v[1].v[0], m.v[2].v[0], m.v[3].v[0]),
|
||||||
|
Vec.init(m.v[0].v[1], m.v[1].v[1], m.v[2].v[1], m.v[3].v[1]),
|
||||||
|
Vec.init(m.v[0].v[2], m.v[1].v[2], m.v[2].v[2], m.v[3].v[2]),
|
||||||
|
Vec.init(m.v[0].v[3], m.v[1].v[3], m.v[2].v[3], m.v[3].v[3]),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a 3D matrix which translates coordinates by the given vector.
|
/// Constructs a 3D matrix which scales each dimension by the given vector.
|
||||||
pub inline fn translate(t: math.Vec3) Matrix {
|
pub inline fn scale(s: math.Vec3) Matrix {
|
||||||
return init(
|
return init(
|
||||||
&RowVec.init(1, 0, 0, t.x()),
|
&RowVec.init(s.x(), 0, 0, 0),
|
||||||
&RowVec.init(0, 1, 0, t.y()),
|
&RowVec.init(0, s.y(), 0, 0),
|
||||||
&RowVec.init(0, 0, 1, t.z()),
|
&RowVec.init(0, 0, s.z(), 0),
|
||||||
&RowVec.init(0, 0, 0, 1),
|
&RowVec.init(0, 0, 0, 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a 3D matrix which translates coordinates by the given scalar.
|
/// Constructs a 3D matrix which scales each dimension by the given scalar.
|
||||||
pub inline fn translateScalar(t: Vec.T) Matrix {
|
pub inline fn scaleScalar(s: Vec.T) Matrix {
|
||||||
return translate(math.Vec3.splat(t));
|
return scale(math.Vec3.splat(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the translation component of the matrix.
|
/// Constructs a 3D matrix which translates coordinates by the given vector.
|
||||||
pub inline fn translation(t: *const Matrix) math.Vec3 {
|
pub inline fn translate(t: math.Vec3) Matrix {
|
||||||
return math.Vec3.init(t.v[3].x(), t.v[3].y(), t.v[3].z());
|
return init(
|
||||||
}
|
&RowVec.init(1, 0, 0, t.x()),
|
||||||
|
&RowVec.init(0, 1, 0, t.y()),
|
||||||
|
&RowVec.init(0, 0, 1, t.z()),
|
||||||
|
&RowVec.init(0, 0, 0, 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a 3D matrix which rotates around the X axis by `angle_radians`.
|
/// Constructs a 3D matrix which translates coordinates by the given scalar.
|
||||||
pub inline fn rotateX(angle_radians: f32) Matrix {
|
pub inline fn translateScalar(t: Vec.T) Matrix {
|
||||||
const c = math.cos(angle_radians);
|
return translate(math.Vec3.splat(t));
|
||||||
const s = math.sin(angle_radians);
|
}
|
||||||
return Matrix.init(
|
|
||||||
&RowVec.init(1, 0, 0, 0),
|
|
||||||
&RowVec.init(0, c, -s, 0),
|
|
||||||
&RowVec.init(0, s, c, 0),
|
|
||||||
&RowVec.init(0, 0, 0, 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 3D matrix which rotates around the X axis by `angle_radians`.
|
/// Returns the translation component of the matrix.
|
||||||
pub inline fn rotateY(angle_radians: f32) Matrix {
|
pub inline fn translation(t: *const Matrix) math.Vec3 {
|
||||||
const c = math.cos(angle_radians);
|
return math.Vec3.init(t.v[3].x(), t.v[3].y(), t.v[3].z());
|
||||||
const s = math.sin(angle_radians);
|
}
|
||||||
return Matrix.init(
|
|
||||||
&RowVec.init(c, 0, s, 0),
|
|
||||||
&RowVec.init(0, 1, 0, 0),
|
|
||||||
&RowVec.init(-s, 0, c, 0),
|
|
||||||
&RowVec.init(0, 0, 0, 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a 3D matrix which rotates around the Z axis by `angle_radians`.
|
/// Constructs a 3D matrix which rotates around the X axis by `angle_radians`.
|
||||||
pub inline fn rotateZ(angle_radians: f32) Matrix {
|
pub inline fn rotateX(angle_radians: f32) Matrix {
|
||||||
const c = math.cos(angle_radians);
|
const c = math.cos(angle_radians);
|
||||||
const s = math.sin(angle_radians);
|
const s = math.sin(angle_radians);
|
||||||
return Matrix.init(
|
return Matrix.init(
|
||||||
&RowVec.init(c, -s, 0, 0),
|
&RowVec.init(1, 0, 0, 0),
|
||||||
&RowVec.init(s, c, 0, 0),
|
&RowVec.init(0, c, -s, 0),
|
||||||
&RowVec.init(0, 0, 1, 0),
|
&RowVec.init(0, s, c, 0),
|
||||||
&RowVec.init(0, 0, 0, 1),
|
&RowVec.init(0, 0, 0, 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a 2D projection matrix, aka. an orthographic projection matrix.
|
/// Constructs a 3D matrix which rotates around the X axis by `angle_radians`.
|
||||||
///
|
pub inline fn rotateY(angle_radians: f32) Matrix {
|
||||||
/// First, a cuboid is defined with the parameters:
|
const c = math.cos(angle_radians);
|
||||||
///
|
const s = math.sin(angle_radians);
|
||||||
/// * (right - left) defining the distance between the left and right faces of the cube
|
return Matrix.init(
|
||||||
/// * (top - bottom) defining the distance between the top and bottom faces of the cube
|
&RowVec.init(c, 0, s, 0),
|
||||||
/// * (near - far) defining the distance between the back (near) and front (far) faces of the cube
|
&RowVec.init(0, 1, 0, 0),
|
||||||
///
|
&RowVec.init(-s, 0, c, 0),
|
||||||
/// We then need to construct a projection matrix which converts points in that
|
&RowVec.init(0, 0, 0, 1),
|
||||||
/// cuboid's space into clip space:
|
);
|
||||||
///
|
}
|
||||||
/// https://machengine.org/engine/math/traversing-coordinate-systems/#view---clip-space
|
|
||||||
///
|
|
||||||
/// Normally, in sysgpu/webgpu the depth buffer of floating point values would
|
|
||||||
/// have the range [0, 1] representing [near, far], i.e. a pixel very close to the
|
|
||||||
/// viewer would have a depth value of 0.0, and a pixel very far from the viewer
|
|
||||||
/// would have a depth value of 1.0. But this is an ineffective use of floating
|
|
||||||
/// point precision, a better approach is a reversed depth buffer:
|
|
||||||
///
|
|
||||||
/// * https://webgpu.github.io/webgpu-samples/samples/reversedZ
|
|
||||||
/// * https://developer.nvidia.com/content/depth-precision-visualized
|
|
||||||
///
|
|
||||||
/// Mach mandates the use of a reversed depth buffer, so the returned transformation
|
|
||||||
/// matrix maps to near=1 and far=0.
|
|
||||||
pub inline fn projection2D(v: struct {
|
|
||||||
left: f32,
|
|
||||||
right: f32,
|
|
||||||
bottom: f32,
|
|
||||||
top: f32,
|
|
||||||
near: f32,
|
|
||||||
far: f32,
|
|
||||||
}) Matrix {
|
|
||||||
var p = Matrix.ident;
|
|
||||||
p = p.mul(&Matrix.translate(math.vec3(
|
|
||||||
(v.right + v.left) / (v.left - v.right), // translate X so that the middle of (left, right) maps to x=0 in clip space
|
|
||||||
(v.top + v.bottom) / (v.bottom - v.top), // translate Y so that the middle of (bottom, top) maps to y=0 in clip space
|
|
||||||
v.far / (v.far - v.near), // translate Z so that far maps to z=0
|
|
||||||
)));
|
|
||||||
p = p.mul(&Matrix.scale(math.vec3(
|
|
||||||
2 / (v.right - v.left), // scale X so that [left, right] has a 2 unit range, e.g. [-1, +1]
|
|
||||||
2 / (v.top - v.bottom), // scale Y so that [bottom, top] has a 2 unit range, e.g. [-1, +1]
|
|
||||||
1 / (v.near - v.far), // scale Z so that [near, far] has a 1 unit range, e.g. [0, -1]
|
|
||||||
)));
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => @compileError("Expected Mat3x3, Mat4x4 found '" ++ @typeName(Matrix) ++ "'"),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/// Constructs a 3D matrix which rotates around the Z axis by `angle_radians`.
|
||||||
|
pub inline fn rotateZ(angle_radians: f32) Matrix {
|
||||||
|
const c = math.cos(angle_radians);
|
||||||
|
const s = math.sin(angle_radians);
|
||||||
|
return Matrix.init(
|
||||||
|
&RowVec.init(c, -s, 0, 0),
|
||||||
|
&RowVec.init(s, c, 0, 0),
|
||||||
|
&RowVec.init(0, 0, 1, 0),
|
||||||
|
&RowVec.init(0, 0, 0, 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a 2D projection matrix, aka. an orthographic projection matrix.
|
||||||
|
///
|
||||||
|
/// First, a cuboid is defined with the parameters:
|
||||||
|
///
|
||||||
|
/// * (right - left) defining the distance between the left and right faces of the cube
|
||||||
|
/// * (top - bottom) defining the distance between the top and bottom faces of the cube
|
||||||
|
/// * (near - far) defining the distance between the back (near) and front (far) faces of the cube
|
||||||
|
///
|
||||||
|
/// We then need to construct a projection matrix which converts points in that
|
||||||
|
/// cuboid's space into clip space:
|
||||||
|
///
|
||||||
|
/// https://machengine.org/engine/math/traversing-coordinate-systems/#view---clip-space
|
||||||
|
///
|
||||||
|
/// Normally, in sysgpu/webgpu the depth buffer of floating point values would
|
||||||
|
/// have the range [0, 1] representing [near, far], i.e. a pixel very close to the
|
||||||
|
/// viewer would have a depth value of 0.0, and a pixel very far from the viewer
|
||||||
|
/// would have a depth value of 1.0. But this is an ineffective use of floating
|
||||||
|
/// point precision, a better approach is a reversed depth buffer:
|
||||||
|
///
|
||||||
|
/// * https://webgpu.github.io/webgpu-samples/samples/reversedZ
|
||||||
|
/// * https://developer.nvidia.com/content/depth-precision-visualized
|
||||||
|
///
|
||||||
|
/// Mach mandates the use of a reversed depth buffer, so the returned transformation
|
||||||
|
/// matrix maps to near=1 and far=0.
|
||||||
|
pub inline fn projection2D(v: struct {
|
||||||
|
left: f32,
|
||||||
|
right: f32,
|
||||||
|
bottom: f32,
|
||||||
|
top: f32,
|
||||||
|
near: f32,
|
||||||
|
far: f32,
|
||||||
|
}) Matrix {
|
||||||
|
var p = Matrix.ident;
|
||||||
|
p = p.mul(&Matrix.translate(math.vec3(
|
||||||
|
(v.right + v.left) / (v.left - v.right), // translate X so that the middle of (left, right) maps to x=0 in clip space
|
||||||
|
(v.top + v.bottom) / (v.bottom - v.top), // translate Y so that the middle of (bottom, top) maps to y=0 in clip space
|
||||||
|
v.far / (v.far - v.near), // translate Z so that far maps to z=0
|
||||||
|
)));
|
||||||
|
p = p.mul(&Matrix.scale(math.vec3(
|
||||||
|
2 / (v.right - v.left), // scale X so that [left, right] has a 2 unit range, e.g. [-1, +1]
|
||||||
|
2 / (v.top - v.bottom), // scale Y so that [bottom, top] has a 2 unit range, e.g. [-1, +1]
|
||||||
|
1 / (v.near - v.far), // scale Z so that [near, far] has a 1 unit range, e.g. [0, -1]
|
||||||
|
)));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const mul = Shared.mul;
|
||||||
|
pub const mulVec = Shared.mulVec;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn MatShared(comptime RowVec: type, comptime ColVec: type, comptime Matrix: type) type {
|
||||||
|
return struct {
|
||||||
/// Matrix multiplication a*b
|
/// Matrix multiplication a*b
|
||||||
pub inline fn mul(a: *const Matrix, b: *const Matrix) Matrix {
|
pub inline fn mul(a: *const Matrix, b: *const Matrix) Matrix {
|
||||||
@setEvalBranchQuota(10000);
|
@setEvalBranchQuota(10000);
|
||||||
|
|
@ -417,7 +516,7 @@ pub fn Mat(
|
||||||
result[i] += matrix.v[row].v[i] * vector.v[row];
|
result[i] += matrix.v[row].v[i] * vector.v[row];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vec.Vec(ColVec.n, ColVec.T){ .v = result };
|
return ColVec{ .v = result };
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: the below code was correct in our old implementation, it just needs to be updated
|
// TODO: the below code was correct in our old implementation, it just needs to be updated
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@ const mat = @import("mat.zig");
|
||||||
|
|
||||||
pub fn Quat(comptime Scalar: type) type {
|
pub fn Quat(comptime Scalar: type) type {
|
||||||
return extern struct {
|
return extern struct {
|
||||||
v: vec.Vec(4, Scalar),
|
v: vec.Vec4(Scalar),
|
||||||
|
|
||||||
/// The scalar type of this matrix, e.g. Mat3x3.T == f32
|
/// The scalar type of this matrix, e.g. Mat3x3.T == f32
|
||||||
pub const T = Vec.T;
|
pub const T = Vec.T;
|
||||||
|
|
||||||
/// The underlying Vec type, e.g. math.Vec4, math.Vec4h, math.Vec4d
|
/// The underlying Vec type, e.g. math.Vec4, math.Vec4h, math.Vec4d
|
||||||
pub const Vec = vec.Vec(4, Scalar);
|
pub const Vec = vec.Vec4(Scalar);
|
||||||
|
|
||||||
/// The Vec type used to represent axes, e.g. math.Vec3
|
/// The Vec type used to represent axes, e.g. math.Vec3
|
||||||
pub const Axis = vec.Vec(3, Scalar);
|
pub const Axis = vec.Vec3(Scalar);
|
||||||
|
|
||||||
/// Creates a quaternion from the given x, y, z, and w values
|
/// Creates a quaternion from the given x, y, z, and w values
|
||||||
pub inline fn init(x: T, y: T, z: T, w: T) Quat(T) {
|
pub inline fn init(x: T, y: T, z: T, w: T) Quat(T) {
|
||||||
|
|
|
||||||
272
src/math/ray.zig
272
src/math/ray.zig
|
|
@ -4,7 +4,9 @@ const math = mach.math;
|
||||||
const vec = @import("vec.zig");
|
const vec = @import("vec.zig");
|
||||||
|
|
||||||
// A Ray in three-dimensional space
|
// A Ray in three-dimensional space
|
||||||
pub fn Ray(comptime Vec3P: type) type {
|
pub fn Ray3(comptime Scalar: type) type {
|
||||||
|
const Vec3P = vec.Vec3(Scalar);
|
||||||
|
|
||||||
// Floating point precision, will be either f16, f32, or f64
|
// Floating point precision, will be either f16, f32, or f64
|
||||||
const P: type = Vec3P.T;
|
const P: type = Vec3P.T;
|
||||||
|
|
||||||
|
|
@ -34,159 +36,153 @@ pub fn Ray(comptime Vec3P: type) type {
|
||||||
/// and w represents hit distance t
|
/// and w represents hit distance t
|
||||||
pub const Hit = Vec4P;
|
pub const Hit = Vec4P;
|
||||||
|
|
||||||
pub usingnamespace switch (Vec3P) {
|
// Determine the 3D vector dimension with the largest scalar
|
||||||
math.Vec3, math.Vec3h, math.Vec3d => struct {
|
// value
|
||||||
// Determine the 3D vector dimension with the largest scalar
|
fn maxDim(v: [3]P) u8 {
|
||||||
// value
|
if (v[0] > v[1]) {
|
||||||
fn maxDim(v: [3]P) u8 {
|
if (v[0] > v[2]) {
|
||||||
if (v[0] > v[1]) {
|
return 0;
|
||||||
if (v[0] > v[2]) {
|
} else {
|
||||||
return 0;
|
return 2;
|
||||||
} else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
} else if (v[1] > v[2]) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (v[1] > v[2]) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Algorithm based on:
|
// Algorithm based on:
|
||||||
// https://www.jcgt.org/published/0002/01/05/
|
// https://www.jcgt.org/published/0002/01/05/
|
||||||
/// Check for collision of a ray and a triangle in 3D space.
|
/// Check for collision of a ray and a triangle in 3D space.
|
||||||
/// Triangle winding, which determines front- and backface of
|
/// Triangle winding, which determines front- and backface of
|
||||||
/// the given triangle, matters if backface culling is to be
|
/// the given triangle, matters if backface culling is to be
|
||||||
/// enabled. Without backface culling it does not matter for
|
/// enabled. Without backface culling it does not matter for
|
||||||
/// hit detection, however the barycentric coordinates will
|
/// hit detection, however the barycentric coordinates will
|
||||||
/// be negative in case of a backface hit.
|
/// be negative in case of a backface hit.
|
||||||
/// On hit, will return a RayHit which contains distance t
|
/// On hit, will return a RayHit which contains distance t
|
||||||
/// and barycentric coordinates.
|
/// and barycentric coordinates.
|
||||||
pub inline fn triangleIntersect(
|
pub inline fn triangleIntersect(
|
||||||
ray: *const Ray(Vec3P),
|
ray: *const Ray3(P),
|
||||||
va: *const Vec3P,
|
va: *const Vec3P,
|
||||||
vb: *const Vec3P,
|
vb: *const Vec3P,
|
||||||
vc: *const Vec3P,
|
vc: *const Vec3P,
|
||||||
backface_culling: bool,
|
backface_culling: bool,
|
||||||
) ?Hit {
|
) ?Hit {
|
||||||
const kz: u8 = maxDim([3]P{
|
const kz: u8 = maxDim([3]P{
|
||||||
@abs(ray.direction.v[0]),
|
@abs(ray.direction.v[0]),
|
||||||
@abs(ray.direction.v[1]),
|
@abs(ray.direction.v[1]),
|
||||||
@abs(ray.direction.v[2]),
|
@abs(ray.direction.v[2]),
|
||||||
});
|
});
|
||||||
if (ray.direction.v[kz] == 0.0) {
|
if (ray.direction.v[kz] == 0.0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var kx: u8 = kz + 1;
|
var kx: u8 = kz + 1;
|
||||||
if (kx == 3)
|
if (kx == 3)
|
||||||
kx = 0;
|
kx = 0;
|
||||||
var ky: u8 = kx + 1;
|
var ky: u8 = kx + 1;
|
||||||
if (ky == 3)
|
if (ky == 3)
|
||||||
ky = 0;
|
ky = 0;
|
||||||
|
|
||||||
if (ray.direction.v[kz] < 0.0) {
|
if (ray.direction.v[kz] < 0.0) {
|
||||||
const tmp = kx;
|
const tmp = kx;
|
||||||
kx = ky;
|
kx = ky;
|
||||||
ky = tmp;
|
ky = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sx: P = ray.direction.v[kx] / ray.direction.v[kz];
|
const sx: P = ray.direction.v[kx] / ray.direction.v[kz];
|
||||||
const sy: P = ray.direction.v[ky] / ray.direction.v[kz];
|
const sy: P = ray.direction.v[ky] / ray.direction.v[kz];
|
||||||
const sz: P = 1.0 / ray.direction.v[kz];
|
const sz: P = 1.0 / ray.direction.v[kz];
|
||||||
|
|
||||||
const a: @Vector(3, P) = va.v - ray.origin.v;
|
const a: @Vector(3, P) = va.v - ray.origin.v;
|
||||||
const b: @Vector(3, P) = vb.v - ray.origin.v;
|
const b: @Vector(3, P) = vb.v - ray.origin.v;
|
||||||
const c: @Vector(3, P) = vc.v - ray.origin.v;
|
const c: @Vector(3, P) = vc.v - ray.origin.v;
|
||||||
|
|
||||||
const ax: P = a[kx] - sx * a[kz];
|
const ax: P = a[kx] - sx * a[kz];
|
||||||
const ay: P = a[ky] - sy * a[kz];
|
const ay: P = a[ky] - sy * a[kz];
|
||||||
const bx: P = b[kx] - sx * b[kz];
|
const bx: P = b[kx] - sx * b[kz];
|
||||||
const by: P = b[ky] - sy * b[kz];
|
const by: P = b[ky] - sy * b[kz];
|
||||||
const cx: P = c[kx] - sx * c[kz];
|
const cx: P = c[kx] - sx * c[kz];
|
||||||
const cy: P = c[ky] - sy * c[kz];
|
const cy: P = c[ky] - sy * c[kz];
|
||||||
|
|
||||||
var u: P = cx * by - cy * bx;
|
var u: P = cx * by - cy * bx;
|
||||||
var v: P = ax * cy - ay * cx;
|
var v: P = ax * cy - ay * cx;
|
||||||
const w: P = bx * ay - by * ax;
|
const w: P = bx * ay - by * ax;
|
||||||
|
|
||||||
// Double precision fallback
|
// Double precision fallback
|
||||||
if (u == 0.0 or v == 0.0 or w == 0.0) {
|
if (u == 0.0 or v == 0.0 or w == 0.0) {
|
||||||
const cxby: PP = @as(PP, @floatCast(cx)) *
|
const cxby: PP = @as(PP, @floatCast(cx)) *
|
||||||
@as(PP, @floatCast(by));
|
@as(PP, @floatCast(by));
|
||||||
const cybx: PP = @as(PP, @floatCast(cy)) *
|
const cybx: PP = @as(PP, @floatCast(cy)) *
|
||||||
@as(PP, @floatCast(bx));
|
@as(PP, @floatCast(bx));
|
||||||
u = @floatCast(cxby - cybx);
|
u = @floatCast(cxby - cybx);
|
||||||
|
|
||||||
const axcy: PP = @as(PP, @floatCast(ax)) *
|
const axcy: PP = @as(PP, @floatCast(ax)) *
|
||||||
@as(PP, @floatCast(cy));
|
@as(PP, @floatCast(cy));
|
||||||
const aycx: PP = @as(PP, @floatCast(ay)) *
|
const aycx: PP = @as(PP, @floatCast(ay)) *
|
||||||
@as(PP, @floatCast(cx));
|
@as(PP, @floatCast(cx));
|
||||||
v = @floatCast(axcy - aycx);
|
v = @floatCast(axcy - aycx);
|
||||||
|
|
||||||
const bxay: PP = @as(PP, @floatCast(bx)) *
|
const bxay: PP = @as(PP, @floatCast(bx)) *
|
||||||
@as(PP, @floatCast(ay));
|
@as(PP, @floatCast(ay));
|
||||||
const byax: PP = @as(PP, @floatCast(by)) *
|
const byax: PP = @as(PP, @floatCast(by)) *
|
||||||
@as(PP, @floatCast(ax));
|
@as(PP, @floatCast(ax));
|
||||||
v = @floatCast(bxay - byax);
|
v = @floatCast(bxay - byax);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backface_culling) {
|
if (backface_culling) {
|
||||||
if (u < 0.0 or v < 0.0 or w < 0.0)
|
if (u < 0.0 or v < 0.0 or w < 0.0)
|
||||||
return null; // no hit
|
return null; // no hit
|
||||||
} else {
|
} else {
|
||||||
if ((u < 0.0 or v < 0.0 or w < 0.0) and
|
if ((u < 0.0 or v < 0.0 or w < 0.0) and
|
||||||
(u > 0.0 or v > 0.0 or w > 0.0))
|
(u > 0.0 or v > 0.0 or w > 0.0))
|
||||||
return null; // no hit
|
return null; // no hit
|
||||||
}
|
}
|
||||||
|
|
||||||
var det: P = u + v + w;
|
var det: P = u + v + w;
|
||||||
if (det == 0.0)
|
if (det == 0.0)
|
||||||
return null; // no hit
|
return null; // no hit
|
||||||
|
|
||||||
// Calculate scaled z-coordinates of vertices and use them
|
// Calculate scaled z-coordinates of vertices and use them
|
||||||
// to calculate the hit distance
|
// to calculate the hit distance
|
||||||
const az: P = sz * a[kz];
|
const az: P = sz * a[kz];
|
||||||
const bz: P = sz * b[kz];
|
const bz: P = sz * b[kz];
|
||||||
const cz: P = sz * c[kz];
|
const cz: P = sz * c[kz];
|
||||||
var t: P = u * az + v * bz + w * cz;
|
var t: P = u * az + v * bz + w * cz;
|
||||||
|
|
||||||
// hit.t counts as a previous hit for backface culling,
|
// hit.t counts as a previous hit for backface culling,
|
||||||
// in which case triangle behind will no longer be
|
// in which case triangle behind will no longer be
|
||||||
// considered a hit.
|
// considered a hit.
|
||||||
// Since Ray.Hit is represented by a Vec4, t is the last
|
// Since Ray.Hit is represented by a Vec4, t is the last
|
||||||
// element of that vector
|
// element of that vector
|
||||||
var hit: Hit = Vec4P.init(
|
var hit: Hit = Vec4P.init(
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
math.inf(f32),
|
math.inf(f32),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (backface_culling) {
|
if (backface_culling) {
|
||||||
if ((t < 0.0) or (t > hit.v[3] * det))
|
if ((t < 0.0) or (t > hit.v[3] * det))
|
||||||
return null; // no hit
|
return null; // no hit
|
||||||
} else {
|
} else {
|
||||||
if (det < 0) {
|
if (det < 0) {
|
||||||
t = -t;
|
t = -t;
|
||||||
det = -det;
|
det = -det;
|
||||||
}
|
|
||||||
if ((t < 0.0) or (t > hit.v[3] * det))
|
|
||||||
return null; // no hit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize u, v, w and t
|
|
||||||
const rcp_det = 1.0 / det;
|
|
||||||
hit.v[0] = u * rcp_det;
|
|
||||||
hit.v[1] = v * rcp_det;
|
|
||||||
hit.v[2] = w * rcp_det;
|
|
||||||
hit.v[3] = t * rcp_det;
|
|
||||||
|
|
||||||
return hit;
|
|
||||||
}
|
}
|
||||||
},
|
if ((t < 0.0) or (t > hit.v[3] * det))
|
||||||
else => @compileError("Expected Vec3, Vec3h, or Vec3d, found '" ++
|
return null; // no hit
|
||||||
@typeName(Vec3P) ++ "'"),
|
}
|
||||||
};
|
|
||||||
|
// Normalize u, v, w and t
|
||||||
|
const rcp_det = 1.0 / det;
|
||||||
|
hit.v[0] = u * rcp_det;
|
||||||
|
hit.v[1] = v * rcp_det;
|
||||||
|
hit.v[2] = w * rcp_det;
|
||||||
|
hit.v[3] = t * rcp_det;
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
369
src/math/vec.zig
369
src/math/vec.zig
|
|
@ -8,145 +8,272 @@ const quat = @import("quat.zig");
|
||||||
|
|
||||||
pub const VecComponent = enum { x, y, z, w };
|
pub const VecComponent = enum { x, y, z, w };
|
||||||
|
|
||||||
pub fn Vec(comptime n_value: usize, comptime Scalar: type) type {
|
pub fn Vec2(comptime Scalar: type) type {
|
||||||
return extern struct {
|
return extern struct {
|
||||||
v: Vector,
|
v: Vector,
|
||||||
|
|
||||||
/// The vector dimension size, e.g. Vec3.n == 3
|
/// The vector dimension size, e.g. Vec3.n == 3
|
||||||
pub const n = n_value;
|
pub const n = 2;
|
||||||
|
|
||||||
/// The scalar type of this vector, e.g. Vec3.T == f32
|
/// The scalar type of this vector, e.g. Vec3.T == f32
|
||||||
pub const T = Scalar;
|
pub const T = Scalar;
|
||||||
|
|
||||||
// The underlying @Vector type
|
// The underlying @Vector type
|
||||||
pub const Vector = @Vector(n_value, Scalar);
|
pub const Vector = @Vector(n, Scalar);
|
||||||
|
|
||||||
const VecN = @This();
|
const VecN = @This();
|
||||||
|
|
||||||
pub usingnamespace switch (VecN.n) {
|
const Shared = VecShared(Scalar, VecN);
|
||||||
inline 2 => struct {
|
|
||||||
pub inline fn init(xs: Scalar, ys: Scalar) VecN {
|
|
||||||
return .{ .v = .{ xs, ys } };
|
|
||||||
}
|
|
||||||
pub inline fn fromInt(xs: anytype, ys: anytype) VecN {
|
|
||||||
return .{ .v = .{ @floatFromInt(xs), @floatFromInt(ys) } };
|
|
||||||
}
|
|
||||||
pub inline fn x(v: *const VecN) Scalar {
|
|
||||||
return v.v[0];
|
|
||||||
}
|
|
||||||
pub inline fn y(v: *const VecN) Scalar {
|
|
||||||
return v.v[1];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inline 3 => struct {
|
|
||||||
pub inline fn init(xs: Scalar, ys: Scalar, zs: Scalar) VecN {
|
|
||||||
return .{ .v = .{ xs, ys, zs } };
|
|
||||||
}
|
|
||||||
pub inline fn fromInt(xs: anytype, ys: anytype, zs: anytype) VecN {
|
|
||||||
return .{ .v = .{ @floatFromInt(xs), @floatFromInt(ys), @floatFromInt(zs) } };
|
|
||||||
}
|
|
||||||
pub inline fn x(v: *const VecN) Scalar {
|
|
||||||
return v.v[0];
|
|
||||||
}
|
|
||||||
pub inline fn y(v: *const VecN) Scalar {
|
|
||||||
return v.v[1];
|
|
||||||
}
|
|
||||||
pub inline fn z(v: *const VecN) Scalar {
|
|
||||||
return v.v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn swizzle(
|
pub inline fn init(xs: Scalar, ys: Scalar) VecN {
|
||||||
v: *const VecN,
|
return .{ .v = .{ xs, ys } };
|
||||||
xc: VecComponent,
|
}
|
||||||
yc: VecComponent,
|
pub inline fn fromInt(xs: anytype, ys: anytype) VecN {
|
||||||
zc: VecComponent,
|
return .{ .v = .{ @floatFromInt(xs), @floatFromInt(ys) } };
|
||||||
) VecN {
|
}
|
||||||
return .{ .v = @shuffle(VecN.T, v.v, undefined, [3]T{
|
pub inline fn x(v: *const VecN) Scalar {
|
||||||
@intFromEnum(xc),
|
return v.v[0];
|
||||||
@intFromEnum(yc),
|
}
|
||||||
@intFromEnum(zc),
|
pub inline fn y(v: *const VecN) Scalar {
|
||||||
}) };
|
return v.v[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the cross product between vector a and b.
|
pub const add = Shared.add;
|
||||||
/// This can be done only in 3D and required inputs are Vec3.
|
pub const sub = Shared.sub;
|
||||||
pub inline fn cross(a: *const VecN, b: *const VecN) VecN {
|
pub const div = Shared.div;
|
||||||
// https://gamemath.com/book/vectors.html#cross_product
|
pub const mul = Shared.mul;
|
||||||
const s1 = a.swizzle(.y, .z, .x)
|
pub const addScalar = Shared.addScalar;
|
||||||
.mul(&b.swizzle(.z, .x, .y));
|
pub const subScalar = Shared.subScalar;
|
||||||
const s2 = a.swizzle(.z, .x, .y)
|
pub const divScalar = Shared.divScalar;
|
||||||
.mul(&b.swizzle(.y, .z, .x));
|
pub const mulScalar = Shared.mulScalar;
|
||||||
return s1.sub(&s2);
|
pub const less = Shared.less;
|
||||||
}
|
pub const lessEq = Shared.lessEq;
|
||||||
|
pub const greater = Shared.greater;
|
||||||
|
pub const greaterEq = Shared.greaterEq;
|
||||||
|
pub const splat = Shared.splat;
|
||||||
|
pub const len2 = Shared.len2;
|
||||||
|
pub const len = Shared.len;
|
||||||
|
pub const normalize = Shared.normalize;
|
||||||
|
pub const dir = Shared.dir;
|
||||||
|
pub const dist2 = Shared.dist2;
|
||||||
|
pub const dist = Shared.dist;
|
||||||
|
pub const lerp = Shared.lerp;
|
||||||
|
pub const dot = Shared.dot;
|
||||||
|
pub const max = Shared.max;
|
||||||
|
pub const min = Shared.min;
|
||||||
|
pub const inverse = Shared.inverse;
|
||||||
|
pub const negate = Shared.negate;
|
||||||
|
pub const maxScalar = Shared.maxScalar;
|
||||||
|
pub const minScalar = Shared.minScalar;
|
||||||
|
pub const eqlApprox = Shared.eqlApprox;
|
||||||
|
pub const eql = Shared.eql;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Vector * Matrix multiplication
|
pub fn Vec3(comptime Scalar: type) type {
|
||||||
pub inline fn mulMat(vector: *const VecN, matrix: *const mat.Mat(3, 3, Vec(3, T))) VecN {
|
return extern struct {
|
||||||
var result = [_]VecN.T{0} ** 3;
|
v: Vector,
|
||||||
inline for (0..3) |i| {
|
|
||||||
inline for (0..3) |j| {
|
|
||||||
result[i] += vector.v[j] * matrix.v[i].v[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .{ .v = result };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vector * Quat multiplication
|
/// The vector dimension size, e.g. Vec3.n == 3
|
||||||
/// https://github.com/greggman/wgpu-matrix/blob/main/src/vec3-impl.ts#L718
|
pub const n = 3;
|
||||||
pub inline fn mulQuat(v: *const VecN, q: *const quat.Quat(Scalar)) VecN {
|
|
||||||
const qx = q.v.x();
|
|
||||||
const qy = q.v.y();
|
|
||||||
const qz = q.v.z();
|
|
||||||
const w2 = q.v.w() * 2;
|
|
||||||
|
|
||||||
const vx = v.x();
|
/// The scalar type of this vector, e.g. Vec3.T == f32
|
||||||
const vy = v.y();
|
pub const T = Scalar;
|
||||||
const vz = v.z();
|
|
||||||
|
|
||||||
const uv_x = qy * vz - qz * vy;
|
// The underlying @Vector type
|
||||||
const uv_y = qz * vx - qx * vz;
|
pub const Vector = @Vector(n, Scalar);
|
||||||
const uv_z = qx * vy - qy * vx;
|
|
||||||
|
|
||||||
return math.vec3(
|
const VecN = @This();
|
||||||
vx + uv_x * w2 + (qy * uv_z - qz * uv_y) * 2,
|
|
||||||
vy + uv_y * w2 + (qz * uv_x - qx * uv_z) * 2,
|
|
||||||
vz + uv_z * w2 + (qz * uv_y - qy * uv_x) * 2,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inline 4 => struct {
|
|
||||||
pub inline fn init(xs: Scalar, ys: Scalar, zs: Scalar, ws: Scalar) VecN {
|
|
||||||
return .{ .v = .{ xs, ys, zs, ws } };
|
|
||||||
}
|
|
||||||
pub inline fn fromInt(xs: anytype, ys: anytype, zs: anytype, ws: anytype) VecN {
|
|
||||||
return .{ .v = .{ @floatFromInt(xs), @floatFromInt(ys), @floatFromInt(zs), @floatFromInt(ws) } };
|
|
||||||
}
|
|
||||||
pub inline fn x(v: *const VecN) Scalar {
|
|
||||||
return v.v[0];
|
|
||||||
}
|
|
||||||
pub inline fn y(v: *const VecN) Scalar {
|
|
||||||
return v.v[1];
|
|
||||||
}
|
|
||||||
pub inline fn z(v: *const VecN) Scalar {
|
|
||||||
return v.v[2];
|
|
||||||
}
|
|
||||||
pub inline fn w(v: *const VecN) Scalar {
|
|
||||||
return v.v[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vector * Matrix multiplication
|
const Shared = VecShared(Scalar, VecN);
|
||||||
pub inline fn mulMat(vector: *const VecN, matrix: *const mat.Mat(4, 4, Vec(4, T))) VecN {
|
|
||||||
var result = [_]VecN.T{0} ** 4;
|
|
||||||
inline for (0..4) |i| {
|
|
||||||
inline for (0..4) |j| {
|
|
||||||
result[i] += vector.v[j] * matrix.v[i].v[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .{ .v = result };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => @compileError("Expected Vec2, Vec3, Vec4, found '" ++ @typeName(VecN) ++ "'"),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
pub inline fn init(xs: Scalar, ys: Scalar, zs: Scalar) VecN {
|
||||||
|
return .{ .v = .{ xs, ys, zs } };
|
||||||
|
}
|
||||||
|
pub inline fn fromInt(xs: anytype, ys: anytype, zs: anytype) VecN {
|
||||||
|
return .{ .v = .{ @floatFromInt(xs), @floatFromInt(ys), @floatFromInt(zs) } };
|
||||||
|
}
|
||||||
|
pub inline fn x(v: *const VecN) Scalar {
|
||||||
|
return v.v[0];
|
||||||
|
}
|
||||||
|
pub inline fn y(v: *const VecN) Scalar {
|
||||||
|
return v.v[1];
|
||||||
|
}
|
||||||
|
pub inline fn z(v: *const VecN) Scalar {
|
||||||
|
return v.v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn swizzle(
|
||||||
|
v: *const VecN,
|
||||||
|
xc: VecComponent,
|
||||||
|
yc: VecComponent,
|
||||||
|
zc: VecComponent,
|
||||||
|
) VecN {
|
||||||
|
return .{ .v = @shuffle(VecN.T, v.v, undefined, [3]T{
|
||||||
|
@intFromEnum(xc),
|
||||||
|
@intFromEnum(yc),
|
||||||
|
@intFromEnum(zc),
|
||||||
|
}) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the cross product between vector a and b.
|
||||||
|
/// This can be done only in 3D and required inputs are Vec3.
|
||||||
|
pub inline fn cross(a: *const VecN, b: *const VecN) VecN {
|
||||||
|
// https://gamemath.com/book/vectors.html#cross_product
|
||||||
|
const s1 = a.swizzle(.y, .z, .x)
|
||||||
|
.mul(&b.swizzle(.z, .x, .y));
|
||||||
|
const s2 = a.swizzle(.z, .x, .y)
|
||||||
|
.mul(&b.swizzle(.y, .z, .x));
|
||||||
|
return s1.sub(&s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vector * Matrix multiplication
|
||||||
|
pub inline fn mulMat(vector: *const VecN, matrix: *const mat.Mat3x3(T)) VecN {
|
||||||
|
var result = [_]VecN.T{0} ** 3;
|
||||||
|
inline for (0..3) |i| {
|
||||||
|
inline for (0..3) |j| {
|
||||||
|
result[i] += vector.v[j] * matrix.v[i].v[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .{ .v = result };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vector * Quat multiplication
|
||||||
|
/// https://github.com/greggman/wgpu-matrix/blob/main/src/vec3-impl.ts#L718
|
||||||
|
pub inline fn mulQuat(v: *const VecN, q: *const quat.Quat(Scalar)) VecN {
|
||||||
|
const qx = q.v.x();
|
||||||
|
const qy = q.v.y();
|
||||||
|
const qz = q.v.z();
|
||||||
|
const w2 = q.v.w() * 2;
|
||||||
|
|
||||||
|
const vx = v.x();
|
||||||
|
const vy = v.y();
|
||||||
|
const vz = v.z();
|
||||||
|
|
||||||
|
const uv_x = qy * vz - qz * vy;
|
||||||
|
const uv_y = qz * vx - qx * vz;
|
||||||
|
const uv_z = qx * vy - qy * vx;
|
||||||
|
|
||||||
|
return math.vec3(
|
||||||
|
vx + uv_x * w2 + (qy * uv_z - qz * uv_y) * 2,
|
||||||
|
vy + uv_y * w2 + (qz * uv_x - qx * uv_z) * 2,
|
||||||
|
vz + uv_z * w2 + (qz * uv_y - qy * uv_x) * 2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const add = Shared.add;
|
||||||
|
pub const sub = Shared.sub;
|
||||||
|
pub const div = Shared.div;
|
||||||
|
pub const mul = Shared.mul;
|
||||||
|
pub const addScalar = Shared.addScalar;
|
||||||
|
pub const subScalar = Shared.subScalar;
|
||||||
|
pub const divScalar = Shared.divScalar;
|
||||||
|
pub const mulScalar = Shared.mulScalar;
|
||||||
|
pub const less = Shared.less;
|
||||||
|
pub const lessEq = Shared.lessEq;
|
||||||
|
pub const greater = Shared.greater;
|
||||||
|
pub const greaterEq = Shared.greaterEq;
|
||||||
|
pub const splat = Shared.splat;
|
||||||
|
pub const len2 = Shared.len2;
|
||||||
|
pub const len = Shared.len;
|
||||||
|
pub const normalize = Shared.normalize;
|
||||||
|
pub const dir = Shared.dir;
|
||||||
|
pub const dist2 = Shared.dist2;
|
||||||
|
pub const dist = Shared.dist;
|
||||||
|
pub const lerp = Shared.lerp;
|
||||||
|
pub const dot = Shared.dot;
|
||||||
|
pub const max = Shared.max;
|
||||||
|
pub const min = Shared.min;
|
||||||
|
pub const inverse = Shared.inverse;
|
||||||
|
pub const negate = Shared.negate;
|
||||||
|
pub const maxScalar = Shared.maxScalar;
|
||||||
|
pub const minScalar = Shared.minScalar;
|
||||||
|
pub const eqlApprox = Shared.eqlApprox;
|
||||||
|
pub const eql = Shared.eql;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Vec4(comptime Scalar: type) type {
|
||||||
|
return extern struct {
|
||||||
|
v: Vector,
|
||||||
|
|
||||||
|
/// The vector dimension size, e.g. Vec3.n == 3
|
||||||
|
pub const n = 4;
|
||||||
|
|
||||||
|
/// The scalar type of this vector, e.g. Vec3.T == f32
|
||||||
|
pub const T = Scalar;
|
||||||
|
|
||||||
|
// The underlying @Vector type
|
||||||
|
pub const Vector = @Vector(n, Scalar);
|
||||||
|
|
||||||
|
const VecN = @This();
|
||||||
|
|
||||||
|
const Shared = VecShared(Scalar, VecN);
|
||||||
|
|
||||||
|
pub inline fn init(xs: Scalar, ys: Scalar, zs: Scalar, ws: Scalar) VecN {
|
||||||
|
return .{ .v = .{ xs, ys, zs, ws } };
|
||||||
|
}
|
||||||
|
pub inline fn fromInt(xs: anytype, ys: anytype, zs: anytype, ws: anytype) VecN {
|
||||||
|
return .{ .v = .{ @floatFromInt(xs), @floatFromInt(ys), @floatFromInt(zs), @floatFromInt(ws) } };
|
||||||
|
}
|
||||||
|
pub inline fn x(v: *const VecN) Scalar {
|
||||||
|
return v.v[0];
|
||||||
|
}
|
||||||
|
pub inline fn y(v: *const VecN) Scalar {
|
||||||
|
return v.v[1];
|
||||||
|
}
|
||||||
|
pub inline fn z(v: *const VecN) Scalar {
|
||||||
|
return v.v[2];
|
||||||
|
}
|
||||||
|
pub inline fn w(v: *const VecN) Scalar {
|
||||||
|
return v.v[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vector * Matrix multiplication
|
||||||
|
pub inline fn mulMat(vector: *const VecN, matrix: *const mat.Mat4x4(T)) VecN {
|
||||||
|
var result = [_]VecN.T{0} ** 4;
|
||||||
|
inline for (0..4) |i| {
|
||||||
|
inline for (0..4) |j| {
|
||||||
|
result[i] += vector.v[j] * matrix.v[i].v[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .{ .v = result };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const add = Shared.add;
|
||||||
|
pub const sub = Shared.sub;
|
||||||
|
pub const div = Shared.div;
|
||||||
|
pub const mul = Shared.mul;
|
||||||
|
pub const addScalar = Shared.addScalar;
|
||||||
|
pub const subScalar = Shared.subScalar;
|
||||||
|
pub const divScalar = Shared.divScalar;
|
||||||
|
pub const mulScalar = Shared.mulScalar;
|
||||||
|
pub const less = Shared.less;
|
||||||
|
pub const lessEq = Shared.lessEq;
|
||||||
|
pub const greater = Shared.greater;
|
||||||
|
pub const greaterEq = Shared.greaterEq;
|
||||||
|
pub const splat = Shared.splat;
|
||||||
|
pub const len2 = Shared.len2;
|
||||||
|
pub const len = Shared.len;
|
||||||
|
pub const normalize = Shared.normalize;
|
||||||
|
pub const dir = Shared.dir;
|
||||||
|
pub const dist2 = Shared.dist2;
|
||||||
|
pub const dist = Shared.dist;
|
||||||
|
pub const lerp = Shared.lerp;
|
||||||
|
pub const dot = Shared.dot;
|
||||||
|
pub const max = Shared.max;
|
||||||
|
pub const min = Shared.min;
|
||||||
|
pub const inverse = Shared.inverse;
|
||||||
|
pub const negate = Shared.negate;
|
||||||
|
pub const maxScalar = Shared.maxScalar;
|
||||||
|
pub const minScalar = Shared.minScalar;
|
||||||
|
pub const eqlApprox = Shared.eqlApprox;
|
||||||
|
pub const eql = Shared.eql;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn VecShared(comptime Scalar: type, comptime VecN: type) type {
|
||||||
|
return struct {
|
||||||
/// Element-wise addition
|
/// Element-wise addition
|
||||||
pub inline fn add(a: *const VecN, b: *const VecN) VecN {
|
pub inline fn add(a: *const VecN, b: *const VecN) VecN {
|
||||||
return .{ .v = a.v + b.v };
|
return .{ .v = a.v + b.v };
|
||||||
|
|
@ -377,10 +504,10 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type {
|
||||||
|
|
||||||
/// Checks for approximate (absolute tolerance) equality between two vectors
|
/// Checks for approximate (absolute tolerance) equality between two vectors
|
||||||
/// of the same type and dimensions
|
/// of the same type and dimensions
|
||||||
pub inline fn eqlApprox(a: *const VecN, b: *const VecN, tolerance: T) bool {
|
pub inline fn eqlApprox(a: *const VecN, b: *const VecN, tolerance: Scalar) bool {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < VecN.n) : (i += 1) {
|
while (i < VecN.n) : (i += 1) {
|
||||||
if (!math.eql(T, a.v[i], b.v[i], tolerance)) {
|
if (!math.eql(Scalar, a.v[i], b.v[i], tolerance)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -390,7 +517,7 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type {
|
||||||
/// Checks for approximate (absolute epsilon tolerance) equality
|
/// Checks for approximate (absolute epsilon tolerance) equality
|
||||||
/// between two vectors of the same type and dimensions
|
/// between two vectors of the same type and dimensions
|
||||||
pub inline fn eql(a: *const VecN, b: *const VecN) bool {
|
pub inline fn eql(a: *const VecN, b: *const VecN) bool {
|
||||||
return a.eqlApprox(b, math.eps(T));
|
return a.eqlApprox(b, math.eps(Scalar));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue