From fe517f3efbaa56864920c59de671a28aaf6b3f77 Mon Sep 17 00:00:00 2001 From: Stephen Gutekanst Date: Sat, 9 Sep 2023 18:24:10 -0700 Subject: [PATCH] math: improve debug build performance Signed-off-by: Stephen Gutekanst --- src/math/mat.zig | 183 +++++++++++++++++++++++++---------------------- src/math/vec.zig | 82 ++++++++++----------- 2 files changed, 137 insertions(+), 128 deletions(-) diff --git a/src/math/mat.zig b/src/math/mat.zig index 1d00bfad..dbf59c3e 100644 --- a/src/math/mat.zig +++ b/src/math/mat.zig @@ -49,15 +49,15 @@ pub fn Mat( /// Identity matrix pub const ident = switch (Matrix) { inline math.Mat3x3, math.Mat3x3h, math.Mat3x3d => Matrix.init( - RowVec.init(1, 0, 0), - RowVec.init(0, 1, 0), - RowVec.init(0, 0, 1), + &RowVec.init(1, 0, 0), + &RowVec.init(0, 1, 0), + &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), + &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) ++ "'"), }; @@ -84,7 +84,7 @@ pub fn Mat( /// ``` /// /// Note that Mach matrices use [column-major storage and column-vectors](https://machengine.org/engine/math/matrix-storage/). - pub inline fn init(r0: RowVec, r1: RowVec, r2: RowVec) Matrix { + 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(), 1), Vec.init(r0.y(), r1.y(), r2.y(), 1), @@ -93,17 +93,21 @@ pub fn Mat( } /// Returns the row `i` of the matrix. - pub inline fn row(m: Matrix, i: usize) RowVec { - return RowVec.init(m.v[0].v[i], m.v[1].v[i], m.v[2].v[i]); + 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: Matrix, i: usize) RowVec { - return RowVec.init(m.v[i].v[0], m.v[i].v[1], m.v[i].v[2]); + 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: Matrix) 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], 1), Vec.init(m.v[0].v[1], m.v[1].v[1], m.v[2].v[1], 1), @@ -115,9 +119,9 @@ pub fn Mat( // TODO: needs tests 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(s.x(), 0, 0), + &RowVec.init(0, s.y(), 0), + &RowVec.init(0, 0, 1), ); } @@ -131,9 +135,9 @@ pub fn Mat( // TODO: needs tests pub inline fn translate(t: math.Vec2) Matrix { return init( - RowVec.init(1, 0, t.x()), - RowVec.init(0, 1, t.y()), - RowVec.init(0, 0, 1), + &RowVec.init(1, 0, t.x()), + &RowVec.init(0, 1, t.y()), + &RowVec.init(0, 0, 1), ); } @@ -164,15 +168,15 @@ pub fn Mat( /// /// ``` /// const m = Mat4x4.init( - /// vec4(1, 0, 0, tx), - /// vec4(0, 1, 0, ty), - /// vec4(0, 0, 1, tz), - /// vec4(0, 0, 0, tw), + /// &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: RowVec, r1: RowVec, r2: RowVec, r3: RowVec) Matrix { + 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()), @@ -182,17 +186,17 @@ pub fn Mat( } /// Returns the row `i` of the matrix. - pub inline fn row(m: Matrix, i: usize) RowVec { - return RowVec.init(m.v[0].v[i], m.v[1].v[i], m.v[2].v[i], m.v[3].v[i]); + pub inline fn row(m: *const Matrix, i: usize) RowVec { + 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] } }; } /// Returns the column `i` of the matrix. - pub inline fn col(m: Matrix, i: usize) RowVec { - return RowVec.init(m.v[i].v[0], m.v[i].v[1], m.v[i].v[2], m.v[i].v[3]); + pub inline fn col(m: *const Matrix, i: usize) RowVec { + 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] } }; } /// Transposes the matrix. - pub inline fn transpose(m: Matrix) 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], 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]), @@ -205,10 +209,10 @@ pub fn Mat( // TODO: needs tests pub inline fn scale(s: math.Vec3) Matrix { return init( - Vec.init(s.x(), 0, 0, 0), - Vec.init(0, s.y(), 0, 0), - Vec.init(0, 0, s.z(), 0), - Vec.init(0, 0, 0, 1), + &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), ); } @@ -222,10 +226,10 @@ pub fn Mat( // TODO: needs tests pub inline fn translate(t: math.Vec3) Matrix { 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), + &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), ); } @@ -237,7 +241,7 @@ pub fn Mat( /// Returns the translation component of the matrix. // TODO: needs tests - pub inline fn translation(t: Matrix) math.Vec3 { + pub inline fn translation(t: *const Matrix) math.Vec3 { return math.Vec3.init(t.v[3].x(), t.v[3].y(), t.v[3].z()); } @@ -246,10 +250,10 @@ pub fn Mat( const c = std.math.cos(angle_radians); const s = std.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), + &RowVec.init(1, 0, 0, 0), + &RowVec.init(0, c, -s, 0), + &RowVec.init(0, s, c, 0), + &RowVec.init(0, 0, 0, 1), ); } @@ -258,10 +262,10 @@ pub fn Mat( const c = std.math.cos(angle_radians); const s = std.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), + &RowVec.init(c, 0, s, 0), + &RowVec.init(0, 1, 0, 0), + &RowVec.init(-s, 0, c, 0), + &RowVec.init(0, 0, 0, 1), ); } @@ -270,10 +274,10 @@ pub fn Mat( const c = std.math.cos(angle_radians); const s = std.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), + &RowVec.init(c, -s, 0, 0), + &RowVec.init(s, c, 0, 0), + &RowVec.init(0, 0, 1, 0), + &RowVec.init(0, 0, 0, 1), ); } @@ -303,10 +307,10 @@ pub fn Mat( const ty = (top + bottom) / (bottom - top); const tz = near / (near - far); return init( - RowVec.init(xx, 0, 0, tx), - RowVec.init(0, yy, 0, ty), - RowVec.init(0, 0, zz, tz), - RowVec.init(0, 0, 0, 1), + &RowVec.init(xx, 0, 0, tx), + &RowVec.init(0, yy, 0, ty), + &RowVec.init(0, 0, zz, tz), + &RowVec.init(0, 0, 0, 1), ); } }, @@ -315,13 +319,18 @@ pub fn Mat( /// Matrix multiplication a*b // TODO: needs tests - pub fn mul(a: Matrix, b: Matrix) Matrix { + pub inline fn mul(a: *const Matrix, b: *const Matrix) Matrix { + @setEvalBranchQuota(10000); var result: Matrix = undefined; inline for (0..Matrix.rows) |row| { inline for (0..Matrix.cols) |col| { var sum: RowVec.T = 0.0; inline for (0..RowVec.n) |i| { - sum += a.row(row).mul(b.col(col)).v[i]; + // Note: we directly access rows/columns below as it is much faster **in + // debug builds**, instead of using these helpers: + // + // sum += a.row(row).mul(&b.col(col)).v[i]; + sum += a.v[i].v[row] * b.v[col].v[i]; } result.v[col].v[row] = sum; } @@ -401,9 +410,9 @@ test "n" { test "init" { try testing.expect(math.Mat3x3, math.mat3x3( - math.vec3(1, 0, 1337), - math.vec3(0, 1, 7331), - math.vec3(0, 0, 1), + &math.vec3(1, 0, 1337), + &math.vec3(0, 1, 7331), + &math.vec3(0, 0, 1), )).eql(math.Mat3x3{ .v = [_]math.Vec4{ math.Vec4.init(1, 0, 0, 1), @@ -436,9 +445,9 @@ test "mat4x4_ident" { test "Mat3x3_row" { const m = math.Mat3x3.init( - math.vec3(0, 1, 2), - math.vec3(3, 4, 5), - math.vec3(6, 7, 8), + &math.vec3(0, 1, 2), + &math.vec3(3, 4, 5), + &math.vec3(6, 7, 8), ); try testing.expect(math.Vec3, math.vec3(0, 1, 2)).eql(m.row(0)); try testing.expect(math.Vec3, math.vec3(3, 4, 5)).eql(m.row(1)); @@ -447,9 +456,9 @@ test "Mat3x3_row" { test "Mat3x3_col" { const m = math.Mat3x3.init( - math.vec3(0, 1, 2), - math.vec3(3, 4, 5), - math.vec3(6, 7, 8), + &math.vec3(0, 1, 2), + &math.vec3(3, 4, 5), + &math.vec3(6, 7, 8), ); try testing.expect(math.Vec3, math.vec3(0, 3, 6)).eql(m.col(0)); try testing.expect(math.Vec3, math.vec3(1, 4, 7)).eql(m.col(1)); @@ -458,10 +467,10 @@ test "Mat3x3_col" { test "Mat4x4_row" { const m = math.Mat4x4.init( - math.vec4(0, 1, 2, 3), - math.vec4(4, 5, 6, 7), - math.vec4(8, 9, 10, 11), - math.vec4(12, 13, 14, 15), + &math.vec4(0, 1, 2, 3), + &math.vec4(4, 5, 6, 7), + &math.vec4(8, 9, 10, 11), + &math.vec4(12, 13, 14, 15), ); try testing.expect(math.Vec4, math.vec4(0, 1, 2, 3)).eql(m.row(0)); try testing.expect(math.Vec4, math.vec4(4, 5, 6, 7)).eql(m.row(1)); @@ -471,10 +480,10 @@ test "Mat4x4_row" { test "Mat4x4_col" { const m = math.Mat4x4.init( - math.vec4(0, 1, 2, 3), - math.vec4(4, 5, 6, 7), - math.vec4(8, 9, 10, 11), - math.vec4(12, 13, 14, 15), + &math.vec4(0, 1, 2, 3), + &math.vec4(4, 5, 6, 7), + &math.vec4(8, 9, 10, 11), + &math.vec4(12, 13, 14, 15), ); try testing.expect(math.Vec4, math.vec4(0, 4, 8, 12)).eql(m.col(0)); try testing.expect(math.Vec4, math.vec4(1, 5, 9, 13)).eql(m.col(1)); @@ -484,29 +493,29 @@ test "Mat4x4_col" { test "Mat3x3_transpose" { const m = math.Mat3x3.init( - math.vec3(0, 1, 2), - math.vec3(3, 4, 5), - math.vec3(6, 7, 8), + &math.vec3(0, 1, 2), + &math.vec3(3, 4, 5), + &math.vec3(6, 7, 8), ); try testing.expect(math.Mat3x3, math.Mat3x3.init( - math.vec3(0, 3, 6), - math.vec3(1, 4, 7), - math.vec3(2, 5, 8), + &math.vec3(0, 3, 6), + &math.vec3(1, 4, 7), + &math.vec3(2, 5, 8), )).eql(m.transpose()); } test "Mat4x4_transpose" { const m = math.Mat4x4.init( - math.vec4(0, 1, 2, 3), - math.vec4(4, 5, 6, 7), - math.vec4(8, 9, 10, 11), - math.vec4(12, 13, 14, 15), + &math.vec4(0, 1, 2, 3), + &math.vec4(4, 5, 6, 7), + &math.vec4(8, 9, 10, 11), + &math.vec4(12, 13, 14, 15), ); try testing.expect(math.Mat4x4, math.Mat4x4.init( - math.vec4(0, 4, 8, 12), - math.vec4(1, 5, 9, 13), - math.vec4(2, 6, 10, 14), - math.vec4(3, 7, 11, 15), + &math.vec4(0, 4, 8, 12), + &math.vec4(1, 5, 9, 13), + &math.vec4(2, 6, 10, 14), + &math.vec4(3, 7, 11, 15), )).eql(m.transpose()); } diff --git a/src/math/vec.zig b/src/math/vec.zig index 89d2271e..3356bcd3 100644 --- a/src/math/vec.zig +++ b/src/math/vec.zig @@ -24,10 +24,10 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { pub inline fn init(xs: Scalar, ys: Scalar) VecN { return .{ .v = .{ xs, ys } }; } - pub inline fn x(v: VecN) Scalar { + pub inline fn x(v: *const VecN) Scalar { return v.v[0]; } - pub inline fn y(v: VecN) Scalar { + pub inline fn y(v: *const VecN) Scalar { return v.v[1]; } }, @@ -35,27 +35,27 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { pub inline fn init(xs: Scalar, ys: Scalar, zs: Scalar) VecN { return .{ .v = .{ xs, ys, zs } }; } - pub inline fn x(v: VecN) Scalar { + pub inline fn x(v: *const VecN) Scalar { return v.v[0]; } - pub inline fn y(v: VecN) Scalar { + pub inline fn y(v: *const VecN) Scalar { return v.v[1]; } - pub inline fn z(v: VecN) Scalar { + pub inline fn z(v: *const VecN) Scalar { return v.v[2]; } // TODO(math): come up with a better strategy for swizzling? - pub inline fn yzw(v: VecN) VecN { + pub inline fn yzw(v: *const VecN) VecN { return VecN.init(v.y(), v.z(), v.w()); } - pub inline fn zxy(v: VecN) VecN { + pub inline fn zxy(v: *const VecN) VecN { return VecN.init(v.z(), v.x(), v.y()); } /// 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: VecN, b: VecN) VecN { + pub inline fn cross(a: *const VecN, b: *const VecN) VecN { // https://gamemath.com/book/vectors.html#cross_product const s1 = a.yzx().mul(b.zxy()); const s2 = a.zxy().mul(b.yzx()); @@ -66,16 +66,16 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { pub inline fn init(xs: Scalar, ys: Scalar, zs: Scalar, ws: Scalar) VecN { return .{ .v = .{ xs, ys, zs, ws } }; } - pub inline fn x(v: VecN) Scalar { + pub inline fn x(v: *const VecN) Scalar { return v.v[0]; } - pub inline fn y(v: VecN) Scalar { + pub inline fn y(v: *const VecN) Scalar { return v.v[1]; } - pub inline fn z(v: VecN) Scalar { + pub inline fn z(v: *const VecN) Scalar { return v.v[2]; } - pub inline fn w(v: VecN) Scalar { + pub inline fn w(v: *const VecN) Scalar { return v.v[3]; } }, @@ -83,66 +83,66 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { }; /// Element-wise addition - pub inline fn add(a: VecN, b: VecN) VecN { + pub inline fn add(a: *const VecN, b: *const VecN) VecN { return .{ .v = a.v + b.v }; } /// Element-wise subtraction - pub inline fn sub(a: VecN, b: VecN) VecN { + pub inline fn sub(a: *const VecN, b: *const VecN) VecN { return .{ .v = a.v - b.v }; } /// Element-wise division - pub inline fn div(a: VecN, b: VecN) VecN { + pub inline fn div(a: *const VecN, b: *const VecN) VecN { return .{ .v = a.v / b.v }; } /// Element-wise multiplication. /// /// See also .cross() - pub inline fn mul(a: VecN, b: VecN) VecN { + pub inline fn mul(a: *const VecN, b: *const VecN) VecN { return .{ .v = a.v * b.v }; } /// Scalar addition - pub inline fn addScalar(a: VecN, s: Scalar) VecN { + pub inline fn addScalar(a: *const VecN, s: Scalar) VecN { return .{ .v = a.v + VecN.splat(s).v }; } /// Scalar subtraction - pub inline fn subScalar(a: VecN, s: Scalar) VecN { + pub inline fn subScalar(a: *const VecN, s: Scalar) VecN { return .{ .v = a.v - VecN.splat(s).v }; } /// Scalar division - pub inline fn divScalar(a: VecN, s: Scalar) VecN { + pub inline fn divScalar(a: *const VecN, s: Scalar) VecN { return .{ .v = a.v / VecN.splat(s).v }; } /// Scalar multiplication. /// /// See .dot() for the dot product - pub inline fn mulScalar(a: VecN, s: Scalar) VecN { + pub inline fn mulScalar(a: *const VecN, s: Scalar) VecN { return .{ .v = a.v * VecN.splat(s).v }; } /// Element-wise a < b - pub inline fn less(a: VecN, b: Scalar) bool { + pub inline fn less(a: *const VecN, b: Scalar) bool { return a.v < b.v; } /// Element-wise a <= b - pub inline fn lessEq(a: VecN, b: Scalar) bool { + pub inline fn lessEq(a: *const VecN, b: Scalar) bool { return a.v <= b.v; } /// Element-wise a > b - pub inline fn greater(a: VecN, b: Scalar) bool { + pub inline fn greater(a: *const VecN, b: Scalar) bool { return a.v > b.v; } /// Element-wise a >= b - pub inline fn greaterEq(a: VecN, b: Scalar) bool { + pub inline fn greaterEq(a: *const VecN, b: Scalar) bool { return a.v >= b.v; } @@ -157,7 +157,7 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { } /// Computes the squared length of the vector. Faster than `len()` - pub inline fn len2(v: VecN) Scalar { + pub inline fn len2(v: *const VecN) Scalar { return switch (VecN.n) { inline 2 => (v.x() * v.x()) + (v.y() * v.y()), inline 3 => (v.x() * v.x()) + (v.y() * v.y()) + (v.z() * v.z()), @@ -167,7 +167,7 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { } /// Computes the length of the vector. - pub inline fn len(v: VecN) Scalar { + pub inline fn len(v: *const VecN) Scalar { return math.sqrt(len2(v)); } @@ -179,8 +179,8 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { /// ``` /// math.vec3(1.0, 2.0, 3.0).normalize(v, 0.00000001); /// ``` - pub inline fn normalize(v: VecN, d0: Scalar) VecN { - return v.div(VecN.splat(v.len() + d0)); + pub inline fn normalize(v: *const VecN, d0: Scalar) VecN { + return v.div(&VecN.splat(v.len() + d0)); } /// Returns the normalized direction vector from points a and b. @@ -191,17 +191,17 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { /// ``` /// var v = a_point.dir(b_point, 0.0000001); /// ``` - pub inline fn dir(a: VecN, b: VecN, d0: Scalar) VecN { + pub inline fn dir(a: *const VecN, b: *const VecN, d0: Scalar) VecN { return b.sub(a).normalize(d0); } /// Calculates the squared distance between points a and b. Faster than `dist()`. - pub inline fn dist2(a: VecN, b: VecN) Scalar { + pub inline fn dist2(a: *const VecN, b: *const VecN) Scalar { return b.sub(a).len2(); } /// Calculates the distance between points a and b. - pub inline fn dist(a: VecN, b: VecN) Scalar { + pub inline fn dist(a: *const VecN, b: *const VecN) Scalar { return math.sqrt(a.dist2(b)); } @@ -211,12 +211,12 @@ pub fn Vec(comptime n_value: usize, comptime Scalar: type) type { /// a.lerp(b, 0.0) == a /// a.lerp(b, 1.0) == b /// ``` - pub inline fn lerp(a: VecN, b: VecN, amount: Scalar) VecN { + pub inline fn lerp(a: *const VecN, b: *const VecN, amount: Scalar) VecN { return a.mulScalar(1.0 - amount).add(b.mulScalar(amount)); } /// Calculates the dot product between vector a and b and returns scalar. - pub inline fn dot(a: VecN, b: VecN) Scalar { + pub inline fn dot(a: *const VecN, b: *const VecN) Scalar { return .{ .v = @reduce(.Add, a.v * b.v) }; } }; @@ -304,14 +304,14 @@ test "normalize_no_nan" { // TODO(math): add basic tests for these: // -// pub inline fn add(a: VecN, b: VecN) VecN { -// pub inline fn sub(a: VecN, b: VecN) VecN { -// pub inline fn div(a: VecN, b: VecN) VecN { -// pub inline fn mul(a: VecN, b: VecN) VecN { -// pub inline fn addScalar(a: VecN, s: Scalar) VecN { -// pub inline fn subScalar(a: VecN, s: Scalar) VecN { -// pub inline fn divScalar(a: VecN, s: Scalar) VecN { -// pub inline fn mulScalar(a: VecN, s: Scalar) VecN { +// pub inline fn add(a: *const VecN, b: *const VecN) VecN { +// pub inline fn sub(a: *const VecN, b: *const VecN) VecN { +// pub inline fn div(a: *const VecN, b: *const VecN) VecN { +// pub inline fn mul(a: *const VecN, b: *const VecN) VecN { +// pub inline fn addScalar(a: *const VecN, s: Scalar) VecN { +// pub inline fn subScalar(a: *const VecN, s: Scalar) VecN { +// pub inline fn divScalar(a: *const VecN, s: Scalar) VecN { +// pub inline fn mulScalar(a: *const VecN, s: Scalar) VecN { // TODO(math): the tests below violate our styleguide (https://machengine.org/about/style/) we // should write new tests loosely based on them: