diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c665f07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +zig-cache +zig-out +.zig-cache +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..dd86e94 --- /dev/null +++ b/build.zig @@ -0,0 +1,38 @@ +const std = @import("std"); +const Mode = std.builtin.OptimizeMode; + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{ + .preferred_optimize_mode = Mode.ReleaseSmall, + }); + + const exe = b.addExecutable(.{ + .name = "newtest", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + b.installArtifact(exe); + + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const test_step = b.step("test", "Run unit tests"); + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..18b54e9 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = "newtest", + .version = "0.0.0", + .dependencies = .{}, + + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..12fea74 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,9 @@ +const std = @import("std"); +const Vec3 = @import("vector.zig").Vec3; + +pub fn main() !void { + const a = Vec3.new(1.0, 2.0, 3.0); + const b = Vec3.new(4.0, 5.0, 6.0); + const c = a.dot(b); + std.debug.print("a dot b = {d}\n", .{c}); +} diff --git a/src/matrix.zig b/src/matrix.zig new file mode 100644 index 0000000..d738795 --- /dev/null +++ b/src/matrix.zig @@ -0,0 +1,125 @@ +const std = @import("std"); +const expect = std.testing.expect; + +/// A 3D matrix. +pub const Mat3 = struct { + m: [3][3]f32, + + /// Suitable constructor? + // pub fn new(m: f32[3][3]) Mat3 {} + + /// Create new identity matrix + pub fn identity() Mat3 { + return Mat3{ + .m = [3][3]f32{ + [_]f32{ 1.0, 0.0, 0.0 }, + [_]f32{ 0.0, 1.0, 0.0 }, + [_]f32{ 0.0, 0.0, 1.0 }, + }, + }; + } + + /// Create scaled matrix + pub fn scale(x: f32, y: f32, z: f32) Mat3 { + return Mat3{ + .m = [3][3]f32{ + [_]f32{ x, 0.0, 0.0 }, + [_]f32{ 0.0, y, 0.0 }, + [_]f32{ 0.0, 0.0, z }, + }, + }; + } + + /// Matrix multiplication + pub fn matmul(self: *const Mat3, other: Mat3) Mat3 { + return Mat3{ + .m = [3][3]f32{ + [_]f32{ + self.m[0][0] * other.m[0][0] + self.m[0][1] * other.m[1][0] + self.m[0][2] * other.m[2][0], + self.m[0][0] * other.m[0][1] + self.m[0][1] * other.m[1][1] + self.m[0][2] * other.m[2][1], + self.m[0][0] * other.m[0][2] + self.m[0][1] * other.m[1][2] + self.m[0][2] * other.m[2][2], + }, + [_]f32{ + self.m[1][0] * other.m[0][0] + self.m[1][1] * other.m[1][0] + self.m[1][2] * other.m[2][0], + self.m[1][0] * other.m[0][1] + self.m[1][1] * other.m[1][1] + self.m[1][2] * other.m[2][1], + self.m[1][0] * other.m[0][2] + self.m[1][1] * other.m[1][2] + self.m[1][2] * other.m[2][2], + }, + [_]f32{ + self.m[2][0] * other.m[0][0] + self.m[2][1] * other.m[1][0] + self.m[2][2] * other.m[2][0], + self.m[2][0] * other.m[0][1] + self.m[2][1] * other.m[1][1] + self.m[2][2] * other.m[2][1], + self.m[2][0] * other.m[0][2] + self.m[2][1] * other.m[1][2] + self.m[2][2] * other.m[2][2], + }, + }, + }; + } + + // TODO: + // pub fn normalize(self: Mat3) Mat3 {} + // pub fn norm(self: *const Mat3) f32 {} + + // TODO: + /// Custom formatter + pub fn format( + self: Mat3, + comptime fmt: []const f32, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = fmt; + _ = options; + + try writer.print("{s} ({}-", .{ + self.name, self.birth_year, + }); + + if (self.death_year) |year| { + try writer.print("{}", .{year}); + } + + try writer.writeAll(")"); + } +}; + +test "Identity" { + const a = Mat3.identity(); + + try expect(a.m[0][0] == 1.0); + try expect(a.m[1][1] == 1.0); + try expect(a.m[2][2] == 1.0); + + try expect(a.m[0][1] == 0.0); +} + +test "Matmul" { + const a = Mat3{ + .m = [3][3]f32{ + [_]f32{ 1.0, 2.0, 3.0 }, + [_]f32{ 4.0, 5.0, 6.0 }, + [_]f32{ 7.0, 8.0, 9.0 }, + }, + }; + + const b = Mat3{ + .m = [3][3]f32{ + [_]f32{ 1.0, 2.0, 3.0 }, + [_]f32{ 4.0, 5.0, 6.0 }, + [_]f32{ 7.0, 8.0, 9.0 }, + }, + }; + + const c = a.matmul(b); + + try expect(c.m[0][0] == 30.0); +} + +test "Scale" { + const a = Mat3.scale(2.0, 3.0, 4.0); + + try expect(a.m[0][0] == 2.0); + try expect(a.m[1][1] == 3.0); + try expect(a.m[2][2] == 4.0); +} + +// test "Invert" {} +// test "Norm" {} +// test "Normalize" {} diff --git a/src/vector.zig b/src/vector.zig new file mode 100644 index 0000000..628f86f --- /dev/null +++ b/src/vector.zig @@ -0,0 +1,45 @@ +const expect = @import("std").testing.expect; + +/// A 3D vector. +pub const Vec3 = struct { + x: f32, + y: f32, + z: f32, + + /// Creates a new vector with the given components. + pub fn new(x: f32, y: f32, z: f32) Vec3 { + return Vec3{ .x = x, .y = y, .z = z }; + } + + /// Returns the dot product of this vector and another. + pub fn dot(self: Vec3, other: Vec3) f32 { + // Sum of dimension-wise multiplication + return self.x * other.x + self.y * other.y + self.z * other.z; + } + + /// Returns the cross product of this vector and another. + pub fn cross(self: Vec3, other: Vec3) Vec3 { + return Vec3{ + .x = self.y * other.z - self.z * other.y, + .y = self.z * other.x - self.x * other.z, + .z = self.x * other.y - self.y * other.x, + }; + } + + // Returns true if this vector is equal to another. + pub fn equals(self: *const Vec3, other: *const Vec3) bool { + return self.x == other.x and self.y == other.y and self.z == other.z; + } +}; + +test "Dot product" { + const a = Vec3{ .x = 1, .y = 2, .z = 3 }; + const b = Vec3{ .x = 4, .y = 5, .z = 6 }; + try expect(a.dot(b) == 32); +} + +test "Cross product" { + const a = Vec3{ .x = 1, .y = 2, .z = 3 }; + const b = Vec3{ .x = 4, .y = 5, .z = 6 }; + try expect(a.cross(b).equals(&Vec3{ .x = -3, .y = 6, .z = -3 })); +}