math: add Mat2x2 (#1130)

This commit is contained in:
Ali Chraghi 2023-12-31 02:27:43 +03:30 committed by GitHub
parent 9cf37cdc39
commit e9489ee560
Failed to generate hash of commit
2 changed files with 179 additions and 7 deletions

View file

@ -51,6 +51,7 @@ pub const Vec2 = vec.Vec(2, f32);
pub const Vec3 = vec.Vec(3, f32); pub const Vec3 = vec.Vec(3, f32);
pub const Vec4 = vec.Vec(4, f32); pub const Vec4 = vec.Vec(4, f32);
pub const Quat = q.Quat(f32); pub const Quat = q.Quat(f32);
pub const Mat2x2 = mat.Mat(2, 2, Vec2);
pub const Mat3x3 = mat.Mat(3, 3, Vec3); pub const Mat3x3 = mat.Mat(3, 3, Vec3);
pub const Mat4x4 = mat.Mat(4, 4, Vec4); pub const Mat4x4 = mat.Mat(4, 4, Vec4);
pub const Ray = ray.Ray(Vec3); pub const Ray = ray.Ray(Vec3);
@ -60,6 +61,7 @@ pub const Vec2h = vec.Vec(2, f16);
pub const Vec3h = vec.Vec(3, f16); pub const Vec3h = vec.Vec(3, f16);
pub const Vec4h = vec.Vec(4, f16); pub const Vec4h = vec.Vec(4, f16);
pub const Quath = q.Quat(f16); pub const Quath = q.Quat(f16);
pub const Mat2x2h = mat.Mat(2, 2, Vec2h);
pub const Mat3x3h = mat.Mat(3, 3, Vec3h); pub const Mat3x3h = mat.Mat(3, 3, Vec3h);
pub const Mat4x4h = mat.Mat(4, 4, Vec4h); pub const Mat4x4h = mat.Mat(4, 4, Vec4h);
pub const Rayh = ray.Ray(Vec3h); pub const Rayh = ray.Ray(Vec3h);
@ -69,6 +71,7 @@ pub const Vec2d = vec.Vec(2, f64);
pub const Vec3d = vec.Vec(3, f64); pub const Vec3d = vec.Vec(3, f64);
pub const Vec4d = vec.Vec(4, f64); pub const Vec4d = vec.Vec(4, f64);
pub const Quatd = q.Quat(f64); pub const Quatd = q.Quat(f64);
pub const Mat2x2d = mat.Mat(2, 2, Vec2d);
pub const Mat3x3d = mat.Mat(3, 3, Vec3d); pub const Mat3x3d = mat.Mat(3, 3, Vec3d);
pub const Mat4x4d = mat.Mat(4, 4, Vec4d); pub const Mat4x4d = mat.Mat(4, 4, Vec4d);
pub const Rayd = ray.Ray(Vec3d); pub const Rayd = ray.Ray(Vec3d);
@ -81,6 +84,7 @@ pub const vec2FromInt = Vec2.fromInt;
pub const vec3FromInt = Vec3.fromInt; pub const vec3FromInt = Vec3.fromInt;
pub const vec4FromInt = Vec4.fromInt; pub const vec4FromInt = Vec4.fromInt;
pub const quat = Quat.init; pub const quat = Quat.init;
pub const mat2x2 = Mat2x2.init;
pub const mat3x3 = Mat3x3.init; pub const mat3x3 = Mat3x3.init;
pub const mat4x4 = Mat4x4.init; pub const mat4x4 = Mat4x4.init;
@ -92,6 +96,7 @@ pub const vec2hFromInt = Vec2h.fromInt;
pub const vec3hFromInt = Vec3h.fromInt; pub const vec3hFromInt = Vec3h.fromInt;
pub const vec4hFromInt = Vec4h.fromInt; pub const vec4hFromInt = Vec4h.fromInt;
pub const quath = Quath.init; pub const quath = Quath.init;
pub const mat2x2h = Mat2x2h.init;
pub const mat3x3h = Mat3x3h.init; pub const mat3x3h = Mat3x3h.init;
pub const mat4x4h = Mat4x4h.init; pub const mat4x4h = Mat4x4h.init;
@ -103,6 +108,7 @@ pub const vec2dFromInt = Vec2d.fromInt;
pub const vec3dFromInt = Vec3d.fromInt; pub const vec3dFromInt = Vec3d.fromInt;
pub const vec4dFromInt = Vec4d.fromInt; pub const vec4dFromInt = Vec4d.fromInt;
pub const quatd = Quatd.init; pub const quatd = Quatd.init;
pub const mat2x2d = Mat2x2d.init;
pub const mat3x3d = Mat3x3d.init; pub const mat3x3d = Mat3x3d.init;
pub const mat4x4d = Mat4x4d.init; pub const mat4x4d = Mat4x4d.init;

View file

@ -51,6 +51,10 @@ pub fn Mat(
/// Identity matrix /// Identity matrix
pub const ident = switch (Matrix) { pub const ident = switch (Matrix) {
inline math.Mat2x2, math.Mat2x2h, math.Mat2x2d => Matrix.init(
&RowVec.init(1, 0),
&RowVec.init(0, 1),
),
inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => Matrix.init( inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => Matrix.init(
&RowVec.init(1, 0, 0), &RowVec.init(1, 0, 0),
&RowVec.init(0, 1, 0), &RowVec.init(0, 1, 0),
@ -66,6 +70,70 @@ pub fn Mat(
}; };
pub usingnamespace switch (Matrix) { pub usingnamespace switch (Matrix) {
inline math.Mat2x2, math.Mat2x2h, math.Mat2x2d => struct {
/// 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),
);
}
/// 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),
);
}
},
inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => struct { inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => struct {
/// Constructs a 3x3 matrix with the given rows. For example to write a translation /// Constructs a 3x3 matrix with the given rows. For example to write a translation
/// matrix like in the left part of this equation: /// matrix like in the left part of this equation:
@ -390,21 +458,26 @@ pub fn Mat(
test "gpu_compatibility" { test "gpu_compatibility" {
// https://www.w3.org/TR/WGSL/#alignment-and-size // https://www.w3.org/TR/WGSL/#alignment-and-size
try testing.expect(usize, 16).eql(@sizeOf(math.Mat2x2));
try testing.expect(usize, 48).eql(@sizeOf(math.Mat3x3)); try testing.expect(usize, 48).eql(@sizeOf(math.Mat3x3));
try testing.expect(usize, 64).eql(@sizeOf(math.Mat4x4)); try testing.expect(usize, 64).eql(@sizeOf(math.Mat4x4));
try testing.expect(usize, 8).eql(@sizeOf(math.Mat2x2h));
try testing.expect(usize, 24).eql(@sizeOf(math.Mat3x3h)); try testing.expect(usize, 24).eql(@sizeOf(math.Mat3x3h));
try testing.expect(usize, 32).eql(@sizeOf(math.Mat4x4h)); try testing.expect(usize, 32).eql(@sizeOf(math.Mat4x4h));
try testing.expect(usize, 48 * 2).eql(@sizeOf(math.Mat3x3d)); // speculative try testing.expect(usize, 32).eql(@sizeOf(math.Mat2x2d)); // speculative
try testing.expect(usize, 64 * 2).eql(@sizeOf(math.Mat4x4d)); // speculative try testing.expect(usize, 96).eql(@sizeOf(math.Mat3x3d)); // speculative
try testing.expect(usize, 128).eql(@sizeOf(math.Mat4x4d)); // speculative
} }
test "zero_struct_overhead" { test "zero_struct_overhead" {
// Proof that using e.g. [3]Vec4 is equal to [3]@Vector(4, f32) // Proof that using e.g. [3]Vec3 is equal to [3]@Vector(3, f32)
try testing.expect(usize, @alignOf([3]@Vector(4, f32))).eql(@alignOf(math.Mat3x3)); try testing.expect(usize, @alignOf([2]@Vector(2, f32))).eql(@alignOf(math.Mat2x2));
try testing.expect(usize, @alignOf([3]@Vector(3, f32))).eql(@alignOf(math.Mat3x3));
try testing.expect(usize, @alignOf([4]@Vector(4, f32))).eql(@alignOf(math.Mat4x4)); try testing.expect(usize, @alignOf([4]@Vector(4, f32))).eql(@alignOf(math.Mat4x4));
try testing.expect(usize, @sizeOf([3]@Vector(4, f32))).eql(@sizeOf(math.Mat3x3)); try testing.expect(usize, @sizeOf([2]@Vector(2, f32))).eql(@sizeOf(math.Mat2x2));
try testing.expect(usize, @sizeOf([3]@Vector(3, f32))).eql(@sizeOf(math.Mat3x3));
try testing.expect(usize, @sizeOf([4]@Vector(4, f32))).eql(@sizeOf(math.Mat4x4)); try testing.expect(usize, @sizeOf([4]@Vector(4, f32))).eql(@sizeOf(math.Mat4x4));
} }
@ -429,7 +502,16 @@ test "init" {
}); });
} }
test "mat3x3_ident" { test "Mat2x2_ident" {
try testing.expect(math.Mat2x2, math.Mat2x2.ident).eql(math.Mat2x2{
.v = [_]math.Vec2{
math.Vec2.init(1, 0),
math.Vec2.init(0, 1),
},
});
}
test "Mat3x3_ident" {
try testing.expect(math.Mat3x3, math.Mat3x3.ident).eql(math.Mat3x3{ try testing.expect(math.Mat3x3, math.Mat3x3.ident).eql(math.Mat3x3{
.v = [_]math.Vec3{ .v = [_]math.Vec3{
math.Vec3.init(1, 0, 0), math.Vec3.init(1, 0, 0),
@ -439,7 +521,7 @@ test "mat3x3_ident" {
}); });
} }
test "mat4x4_ident" { test "Mat4x4_ident" {
try testing.expect(math.Mat4x4, math.Mat4x4.ident).eql(math.Mat4x4{ try testing.expect(math.Mat4x4, math.Mat4x4.ident).eql(math.Mat4x4{
.v = [_]math.Vec4{ .v = [_]math.Vec4{
math.Vec4.init(1, 0, 0, 0), math.Vec4.init(1, 0, 0, 0),
@ -450,6 +532,24 @@ test "mat4x4_ident" {
}); });
} }
test "Mat2x2_row" {
const m = math.Mat2x2.init(
&math.vec2(0, 1),
&math.vec2(2, 3),
);
try testing.expect(math.Vec2, math.vec2(0, 1)).eql(m.row(0));
try testing.expect(math.Vec2, math.vec2(2, 3)).eql(m.row(@TypeOf(m).rows - 1));
}
test "Mat2x2_col" {
const m = math.Mat2x2.init(
&math.vec2(0, 1),
&math.vec2(2, 3),
);
try testing.expect(math.Vec2, math.vec2(0, 2)).eql(m.col(0));
try testing.expect(math.Vec2, math.vec2(1, 3)).eql(m.col(@TypeOf(m).cols - 1));
}
test "Mat3x3_row" { test "Mat3x3_row" {
const m = math.Mat3x3.init( const m = math.Mat3x3.init(
&math.vec3(0, 1, 2), &math.vec3(0, 1, 2),
@ -498,6 +598,17 @@ test "Mat4x4_col" {
try testing.expect(math.Vec4, math.vec4(3, 7, 11, 15)).eql(m.col(@TypeOf(m).cols - 1)); try testing.expect(math.Vec4, math.vec4(3, 7, 11, 15)).eql(m.col(@TypeOf(m).cols - 1));
} }
test "Mat2x2_transpose" {
const m = math.Mat2x2.init(
&math.vec2(0, 1),
&math.vec2(2, 3),
);
try testing.expect(math.Mat2x2, math.Mat2x2.init(
&math.vec2(0, 2),
&math.vec2(1, 3),
)).eql(m.transpose());
}
test "Mat3x3_transpose" { test "Mat3x3_transpose" {
const m = math.Mat3x3.init( const m = math.Mat3x3.init(
&math.vec3(0, 1, 2), &math.vec3(0, 1, 2),
@ -526,6 +637,14 @@ test "Mat4x4_transpose" {
)).eql(m.transpose()); )).eql(m.transpose());
} }
test "Mat2x2_scaleScalar" {
const m = math.Mat2x2.scaleScalar(2);
try testing.expect(math.Mat2x2, math.Mat2x2.init(
&math.vec2(2, 0),
&math.vec2(0, 1),
)).eql(m);
}
test "Mat3x3_scale" { test "Mat3x3_scale" {
const m = math.Mat3x3.scale(math.vec2(2, 3)); const m = math.Mat3x3.scale(math.vec2(2, 3));
try testing.expect(math.Mat3x3, math.Mat3x3.init( try testing.expect(math.Mat3x3, math.Mat3x3.init(
@ -592,6 +711,14 @@ test "Mat3x3_translateScalar" {
)).eql(m); )).eql(m);
} }
test "Mat2x2_translateScalar" {
const m = math.Mat2x2.translateScalar(2);
try testing.expect(math.Mat2x2, math.Mat2x2.init(
&math.vec2(1, 2),
&math.vec2(0, 1),
)).eql(m);
}
test "Mat4x4_translateScalar" { test "Mat4x4_translateScalar" {
const m = math.Mat4x4.translateScalar(2); const m = math.Mat4x4.translateScalar(2);
try testing.expect(math.Mat4x4, math.Mat4x4.init( try testing.expect(math.Mat4x4, math.Mat4x4.init(
@ -612,6 +739,27 @@ test "Mat4x4_translation" {
try testing.expect(math.Vec3, math.vec3(2, 3, 4)).eql(m.translation()); try testing.expect(math.Vec3, math.vec3(2, 3, 4)).eql(m.translation());
} }
test "Mat2x2_mulVec_vec2_ident" {
const v = math.Vec2.splat(1);
const ident = math.Mat2x2.ident;
const expected = v;
var m = math.Mat2x2.mulVec(&ident, &v);
try testing.expect(math.Vec2, expected).eql(m);
}
test "Mat2x2_mulVec_vec2" {
const v = math.Vec2.splat(1);
const mat = math.Mat2x2.init(
&math.vec2(2, 0),
&math.vec2(0, 2),
);
const m = math.Mat2x2.mulVec(&mat, &v);
const expected = math.vec2(2, 2);
try testing.expect(math.Vec2, expected).eql(m);
}
test "Mat3x3_mulVec_vec3_ident" { test "Mat3x3_mulVec_vec3_ident" {
const v = math.Vec3.splat(1); const v = math.Vec3.splat(1);
const ident = math.Mat3x3.ident; const ident = math.Mat3x3.ident;
@ -648,6 +796,24 @@ test "Mat4x4_mulVec_vec4" {
try testing.expect(math.Vec4, expected).eql(m); try testing.expect(math.Vec4, expected).eql(m);
} }
test "Mat2x2_mul" {
const a = math.Mat2x2.init(
&math.vec2(4, 2),
&math.vec2(7, 9),
);
const b = math.Mat2x2.init(
&math.vec2(5, -7),
&math.vec2(6, -3),
);
const c = math.Mat2x2.mul(&a, &b);
const expected = math.Mat2x2.init(
&math.vec2(32, -34),
&math.vec2(89, -76),
);
try testing.expect(math.Mat2x2, expected).eql(c);
}
test "Mat3x3_mul" { test "Mat3x3_mul" {
const a = math.Mat3x3.init( const a = math.Mat3x3.init(
&math.vec3(4, 2, -3), &math.vec3(4, 2, -3),