Use castle for vecmath (doesn't work fully yet)

This commit is contained in:
2026-01-04 17:13:58 +01:00
parent 21c1d2e139
commit fed1e982d2
23 changed files with 424 additions and 1894 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "castle"]
path = castle
url = https://gitea.renati.me/renati/castle.git

View File

@@ -7,10 +7,12 @@ pub fn build(b: *std.Build) !void {
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
const llvm = b.option(bool, "llvm", "Use LLVM and LLD") orelse false; const llvm = b.option(bool, "llvm", "Use LLVM and LLD") orelse false;
const vecmath_dep = b.dependency("vecmath", .{});
const vulkan_dep = b.dependency("vulkan_zig", .{ .registry = b.path("vendor/vk.xml") }); const vulkan_dep = b.dependency("vulkan_zig", .{ .registry = b.path("vendor/vk.xml") });
const zglfw_dep = b.dependency("zglfw", .{ .import_vulkan = true }); const zglfw_dep = b.dependency("zglfw", .{ .import_vulkan = true });
const zstbi_dep = b.dependency("zstbi", .{}); const zstbi_dep = b.dependency("zstbi", .{});
const vecmath_mod = vecmath_dep.module("vecmath");
const vulkan_mod = vulkan_dep.module("vulkan-zig"); const vulkan_mod = vulkan_dep.module("vulkan-zig");
const zglfw_mod = zglfw_dep.module("root"); const zglfw_mod = zglfw_dep.module("root");
const zstbi_mod = zstbi_dep.module("root"); const zstbi_mod = zstbi_dep.module("root");
@@ -25,6 +27,7 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize, .optimize = optimize,
}); });
exe_mod.addImport("vecmath", vecmath_mod);
exe_mod.addImport("vulkan", vulkan_mod); exe_mod.addImport("vulkan", vulkan_mod);
exe_mod.addImport("zglfw", zglfw_mod); exe_mod.addImport("zglfw", zglfw_mod);
exe_mod.addImport("zstbi", zstbi_mod); exe_mod.addImport("zstbi", zstbi_mod);

View File

@@ -5,6 +5,9 @@
.minimum_zig_version = "0.15.2", .minimum_zig_version = "0.15.2",
.dependencies = .{ .dependencies = .{
.vecmath = .{
.path = "castle/packages/vecmath",
},
.vulkan_zig = .{ .vulkan_zig = .{
.url = "git+https://github.com/Snektron/vulkan-zig.git#1446b0b994c2362264cc24513d7c7ec31b469c50", .url = "git+https://github.com/Snektron/vulkan-zig.git#1446b0b994c2362264cc24513d7c7ec31b469c50",
.hash = "vulkan-0.0.0-r7Ytx_VDAwAiMl0YSu2UOkVMIGJN7CeIQaxJR-hUSfD6", .hash = "vulkan-0.0.0-r7Ytx_VDAwAiMl0YSu2UOkVMIGJN7CeIQaxJR-hUSfD6",

1
castle Submodule

Submodule castle added at 7e8103565d

View File

@@ -4,18 +4,17 @@ const std = @import("std");
const c = @import("const.zig"); const c = @import("const.zig");
const math = @import("math.zig"); const math = @import("math.zig");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vm = @import("vecmath");
const Blocks = @import("assets/Blocks.zig"); const Blocks = @import("assets/Blocks.zig");
const Chunk = @import("assets/Chunk.zig"); const Chunk = @import("assets/Chunk.zig");
const Engine = @import("engine/Engine.zig"); const Engine = @import("engine/Engine.zig");
const Iterator2 = math.Iterator2; const Iterator2 = math.Iterator2;
const Vector2Int = math.Vector2Int;
const Vector3Int = math.Vector3Int;
chunks: std.AutoHashMapUnmanaged([3]i16, Chunk), chunks: std.AutoHashMapUnmanaged([3]i16, Chunk),
const RaycastHit = struct { const RaycastHit = struct {
normal_frac: Vector3Int, normal_frac: vm.Vector3Int,
projected_distance_sv: i32, projected_distance_sv: i32,
}; };
@@ -28,40 +27,41 @@ pub fn deinit(self: *Chunks, engine: *Engine, descriptor_pool: vk.DescriptorPool
self.* = undefined; self.* = undefined;
} }
pub fn getVoxelAt(self: *const Chunks, vx: Vector3Int) ?Blocks.Id { pub fn getVoxelAt(self: *const Chunks, vx: vm.Vector3Int) ?Blocks.Id {
const min_ck = Vector3Int.initScalar(std.math.minInt(i16)); const min_ck = vm.Vector3Int.initScalar(std.math.minInt(i16));
const max_ck = Vector3Int.initScalar(std.math.maxInt(i16)); const max_ck = vm.Vector3Int.initScalar(std.math.maxInt(i16));
const ck = vx.divScalar(c.vx_per_ck); const ck = vx.divScalar(c.vx_per_ck);
if (@reduce(.Or, (ck.vector < min_ck.vector) | (ck.vector > max_ck.vector))) { if ((ck.x < min_ck.x) | (ck.y < min_ck.y) | (ck.z < min_ck.z) | (ck.x > max_ck.x) | (ck.y > max_ck.y) | (ck.z > max_ck.z)) {
@branchHint(.unlikely);
return null; return null;
} }
if (self.chunks.get(.{ if (self.chunks.get(.{
@intCast(ck.getX()), @intCast(ck.x),
@intCast(ck.getY()), @intCast(ck.y),
@intCast(ck.getZ()), @intCast(ck.z),
})) |chunk| { })) |chunk| {
const ckvx = vx.modScalar(c.vx_per_ck); const ckvx = vx.modScalar(c.vx_per_ck);
return chunk.blocks[@intCast(ckvx.getZ())][@intCast(ckvx.getY())][@intCast(ckvx.getX())]; return chunk.blocks[@intCast(ckvx.z)][@intCast(ckvx.y)][@intCast(ckvx.x)];
} else { } else {
return .air; return .air;
} }
} }
pub fn isSolid(self: *const Chunks, vx: Vector3Int) bool { pub fn isSolid(self: *const Chunks, vx: vm.Vector3Int) bool {
const maybe_id = getVoxelAt(self, vx); const maybe_id = getVoxelAt(self, vx);
// NOTE `null` is considered solid, as it's out of bounds. // NOTE `null` is considered solid, as it's out of bounds.
return maybe_id != .air; return maybe_id != .air;
} }
pub fn sweepCastDown(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int, distance_sv: i32) ?RaycastHit { pub fn sweepCastDown(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, distance_sv: i32) ?RaycastHit {
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.getX()); const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.x);
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.getY()); const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.y);
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.getX()); const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.x);
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_sv.getY()); const max_y_vx = c.subvoxelsToVoxels(.border_down, max_sv.y);
const start_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.getZ()) - 1; const start_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.z) - 1;
const end_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.getZ() - distance_sv); const end_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.z - distance_sv);
var z_vx: i32 = start_z_vx; var z_vx: i32 = start_z_vx;
while (z_vx >= end_z_vx) : (z_vx -= 1) { while (z_vx >= end_z_vx) : (z_vx -= 1) {
@@ -75,8 +75,8 @@ pub fn sweepCastDown(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue; if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
return .{ return .{
.projected_distance_sv = distance_sv - (min_sv.getZ() - z_sv), .projected_distance_sv = distance_sv - (min_sv.z - z_sv),
.normal_frac = .unit_z_frac, .normal_frac = .init(0, 0, std.math.maxInt(i32)),
}; };
} }
} }
@@ -84,14 +84,14 @@ pub fn sweepCastDown(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int
return null; return null;
} }
pub fn sweepCastUp(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int, distance_sv: i32) ?RaycastHit { pub fn sweepCastUp(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, distance_sv: i32) ?RaycastHit {
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.getX()); const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.x);
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.getY()); const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.y);
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.getX()); const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.x);
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_sv.getY()); const max_y_vx = c.subvoxelsToVoxels(.border_down, max_sv.y);
const start_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.getZ()) + 1; const start_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.z) + 1;
const end_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.getZ() + distance_sv); const end_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.z + distance_sv);
var z_vx: i32 = start_z_vx; var z_vx: i32 = start_z_vx;
while (z_vx <= end_z_vx) : (z_vx += 1) { while (z_vx <= end_z_vx) : (z_vx += 1) {
@@ -105,8 +105,8 @@ pub fn sweepCastUp(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int,
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue; if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
return .{ return .{
.projected_distance_sv = distance_sv - (z_sv - max_sv.getZ()), .projected_distance_sv = distance_sv - (z_sv - max_sv.z),
.normal_frac = .unit_nz_frac, .normal_frac = .init(0, 0, -std.math.maxInt(i32)),
}; };
} }
} }
@@ -114,30 +114,30 @@ pub fn sweepCastUp(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int,
return null; return null;
} }
pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int, ray_sv: Vector2Int) ?RaycastHit { pub fn sweepCastHorizontal(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, ray_sv: vm.Vector2Int) ?RaycastHit {
const min_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.getZ()); const min_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.z);
const max_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.getZ()); const max_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.z);
var hit: ?RaycastHit = null; var hit: ?RaycastHit = null;
var hit_distance_squared = std.math.inf(f32); var hit_distance_squared = std.math.inf(f32);
const fdydx: f32 = @as(f32, @floatFromInt(ray_sv.getY())) / @as(f32, @floatFromInt(ray_sv.getX())); const fdydx: f32 = @as(f32, @floatFromInt(ray_sv.y)) / @as(f32, @floatFromInt(ray_sv.x));
const fdxdy: f32 = @as(f32, @floatFromInt(ray_sv.getX())) / @as(f32, @floatFromInt(ray_sv.getY())); const fdxdy: f32 = @as(f32, @floatFromInt(ray_sv.x)) / @as(f32, @floatFromInt(ray_sv.y));
// Positive X // Positive X
if (ray_sv.getX() > 0) { if (ray_sv.x > 0) {
const x0_sv = max_sv.getX(); const x0_sv = max_sv.x;
const y0_sv = min_sv.getY(); const y0_sv = min_sv.y;
const y1_sv = max_sv.getY(); const y1_sv = max_sv.y;
const start_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv) + 1; const start_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv) + 1;
const end_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv + ray_sv.getX()); const end_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv + ray_sv.x);
var x_vx: i32 = start_x_vx; var x_vx: i32 = start_x_vx;
px: while (x_vx <= end_x_vx) : (x_vx += 1) { px: while (x_vx <= end_x_vx) : (x_vx += 1) {
const x_sv = c.voxelsToSubvoxels(x_vx); const x_sv = c.voxelsToSubvoxels(x_vx);
const min_y_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv); const min_y_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(x_sv - x0_sv, ray_sv.y, ray_sv.x) + y0_sv);
const max_y_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv); const max_y_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(x_sv - x0_sv, ray_sv.y, ray_sv.x) + y1_sv);
var it = Iterator2(i32).init(.{ var it = Iterator2(i32).init(.{
.min = .{ min_y_vx, min_z_vx }, .min = .{ min_y_vx, min_z_vx },
.max = .{ max_y_vx, max_z_vx }, .max = .{ max_y_vx, max_z_vx },
@@ -151,8 +151,8 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
const fdy: f32 = fdx * fdydx; const fdy: f32 = fdx * fdydx;
hit = .{ hit = .{
.projected_distance_sv = ray_sv.getX() - dx, .projected_distance_sv = ray_sv.x - dx,
.normal_frac = .unit_nx_frac, .normal_frac = .init(-std.math.maxInt(i32), 0, 0),
}; };
hit_distance_squared = fdx * fdx + fdy * fdy; hit_distance_squared = fdx * fdx + fdy * fdy;
// std.debug.print("HIT +X ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_x_vx, end_x_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv }); // std.debug.print("HIT +X ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_x_vx, end_x_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv });
@@ -163,19 +163,19 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
} }
// Negative X // Negative X
if (ray_sv.getX() < 0) { if (ray_sv.x < 0) {
const x0_sv = min_sv.getX(); const x0_sv = min_sv.x;
const y0_sv = min_sv.getY(); const y0_sv = min_sv.y;
const y1_sv = max_sv.getY(); const y1_sv = max_sv.y;
const start_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv) - 1; const start_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv) - 1;
const end_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv + ray_sv.getX()); const end_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv + ray_sv.x);
var x_vx: i32 = start_x_vx; var x_vx: i32 = start_x_vx;
nx: while (x_vx >= end_x_vx) : (x_vx -= 1) { nx: while (x_vx >= end_x_vx) : (x_vx -= 1) {
const x_sv = c.voxelsToSubvoxels(x_vx + 1); const x_sv = c.voxelsToSubvoxels(x_vx + 1);
const min_y_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv); const min_y_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(x_sv - x0_sv, ray_sv.y, ray_sv.x) + y0_sv);
const max_y_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv); const max_y_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(x_sv - x0_sv, ray_sv.y, ray_sv.x) + y1_sv);
var it = Iterator2(i32).init(.{ var it = Iterator2(i32).init(.{
.min = .{ min_y_vx, min_z_vx }, .min = .{ min_y_vx, min_z_vx },
.max = .{ max_y_vx, max_z_vx }, .max = .{ max_y_vx, max_z_vx },
@@ -189,8 +189,8 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
const fdy: f32 = fdx * fdydx; const fdy: f32 = fdx * fdydx;
hit = .{ hit = .{
.projected_distance_sv = -(ray_sv.getX() - dx), .projected_distance_sv = -(ray_sv.x - dx),
.normal_frac = .unit_x_frac, .normal_frac = .init(std.math.maxInt(i32), 0, 0),
}; };
hit_distance_squared = fdx * fdx + fdy * fdy; hit_distance_squared = fdx * fdx + fdy * fdy;
// std.debug.print("HIT -X ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_x_vx, end_x_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv }); // std.debug.print("HIT -X ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_x_vx, end_x_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv });
@@ -201,19 +201,19 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
} }
// Positive Y // Positive Y
if (ray_sv.getY() > 0) { if (ray_sv.y > 0) {
const y0_sv = max_sv.getY(); const y0_sv = max_sv.y;
const x0_sv = min_sv.getX(); const x0_sv = min_sv.x;
const x1_sv = max_sv.getX(); const x1_sv = max_sv.x;
const start_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv) + 1; const start_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv) + 1;
const end_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv + ray_sv.getY()); const end_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv + ray_sv.y);
var y_vx = start_y_vx; var y_vx = start_y_vx;
py: while (y_vx <= end_y_vx) : (y_vx += 1) { py: while (y_vx <= end_y_vx) : (y_vx += 1) {
const y_sv = c.voxelsToSubvoxels(y_vx); const y_sv = c.voxelsToSubvoxels(y_vx);
const min_x_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv); const min_x_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(y_sv - y0_sv, ray_sv.x, ray_sv.y) + x0_sv);
const max_x_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv); const max_x_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(y_sv - y0_sv, ray_sv.x, ray_sv.y) + x1_sv);
var it = Iterator2(i32).init(.{ var it = Iterator2(i32).init(.{
.min = .{ min_x_vx, min_z_vx }, .min = .{ min_x_vx, min_z_vx },
.max = .{ max_x_vx, max_z_vx }, .max = .{ max_x_vx, max_z_vx },
@@ -229,8 +229,8 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
const this_hit_distance_squared = fdx * fdx + fdy * fdy; const this_hit_distance_squared = fdx * fdx + fdy * fdy;
if (this_hit_distance_squared < hit_distance_squared) { if (this_hit_distance_squared < hit_distance_squared) {
hit = .{ hit = .{
.projected_distance_sv = ray_sv.getY() - dy, .projected_distance_sv = ray_sv.y - dy,
.normal_frac = .unit_ny_frac, .normal_frac = .init(0, -std.math.maxInt(i32), 0),
}; };
hit_distance_squared = this_hit_distance_squared; hit_distance_squared = this_hit_distance_squared;
// std.debug.print("HIT +Y ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_y_vx, end_y_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv }); // std.debug.print("HIT +Y ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_y_vx, end_y_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv });
@@ -242,19 +242,19 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
} }
// Negative Y // Negative Y
if (ray_sv.getY() < 0.0) { if (ray_sv.y < 0.0) {
const y0_sv = min_sv.getY(); const y0_sv = min_sv.y;
const x0_sv = min_sv.getX(); const x0_sv = min_sv.x;
const x1_sv = max_sv.getX(); const x1_sv = max_sv.x;
const start_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv) - 1; const start_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv) - 1;
const end_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv + ray_sv.getY()); const end_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv + ray_sv.y);
var y_vx = start_y_vx; var y_vx = start_y_vx;
ny: while (y_vx >= end_y_vx) : (y_vx -= 1) { ny: while (y_vx >= end_y_vx) : (y_vx -= 1) {
const y_sv = c.voxelsToSubvoxels(y_vx + 1); const y_sv = c.voxelsToSubvoxels(y_vx + 1);
const min_x_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv); const min_x_vx = c.subvoxelsToVoxels(.border_up, math.wideMulDivFloor(y_sv - y0_sv, ray_sv.x, ray_sv.y) + x0_sv);
const max_x_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv); const max_x_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(y_sv - y0_sv, ray_sv.x, ray_sv.y) + x1_sv);
var it = Iterator2(i32).init(.{ var it = Iterator2(i32).init(.{
.min = .{ min_x_vx, min_z_vx }, .min = .{ min_x_vx, min_z_vx },
.max = .{ max_x_vx, max_z_vx }, .max = .{ max_x_vx, max_z_vx },
@@ -270,8 +270,8 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
const this_hit_distance_squared = fdx * fdx + fdy * fdy; const this_hit_distance_squared = fdx * fdx + fdy * fdy;
if (this_hit_distance_squared < hit_distance_squared) { if (this_hit_distance_squared < hit_distance_squared) {
hit = .{ hit = .{
.projected_distance_sv = -(ray_sv.getY() - dy), .projected_distance_sv = -(ray_sv.y - dy),
.normal_frac = .unit_y_frac, .normal_frac = .init(0, std.math.maxInt(i32), 0),
}; };
hit_distance_squared = this_hit_distance_squared; hit_distance_squared = this_hit_distance_squared;
// std.debug.print("HIT -Y ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_y_vx, end_y_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv }); // std.debug.print("HIT -Y ({X}->{X}) at ({X}, {X}, {X}) [VX] | min_sv={X} max_sv={X} ray_sv={X} | proj_dist={X} \n", .{ start_y_vx, end_y_vx, x_vx, y_vx, z_vx, min_sv.vector, max_sv.vector, ray_sv.vector, hit.?.projected_distance_sv });
@@ -285,64 +285,64 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vect
return hit; return hit;
} }
pub fn raycast(self: *const Chunks, origin_sv: Vector3Int, ray_sv: Vector3Int) ?RaycastHit { pub fn raycast(self: *const Chunks, origin_sv: vm.Vector3Int, ray_sv: vm.Vector3Int) ?RaycastHit {
const end_sv = origin_sv.add(ray_sv); const end_sv = origin_sv.add(ray_sv);
std.debug.print("Raycast from ({d}:{X}, {d}:{X}, {d}:{X}) to ({d}:{X}, {d}:{X}, {d}:{X})\n", .{ std.debug.print("Raycast from ({d}:{X}, {d}:{X}, {d}:{X}) to ({d}:{X}, {d}:{X}, {d}:{X})\n", .{
c.subvoxelsToVoxels(.border_up, origin_sv.getX()), c.subvoxelsToVoxels(.border_up, origin_sv.x),
c.subvoxelsToVoxelSubvoxels(origin_sv.getX()), c.subvoxelsToVoxelSubvoxels(origin_sv.x),
c.subvoxelsToVoxels(.border_up, origin_sv.getY()), c.subvoxelsToVoxels(.border_up, origin_sv.y),
c.subvoxelsToVoxelSubvoxels(origin_sv.getY()), c.subvoxelsToVoxelSubvoxels(origin_sv.y),
c.subvoxelsToVoxels(.border_up, origin_sv.getZ()), c.subvoxelsToVoxels(.border_up, origin_sv.z),
c.subvoxelsToVoxelSubvoxels(origin_sv.getZ()), c.subvoxelsToVoxelSubvoxels(origin_sv.z),
c.subvoxelsToVoxels(.border_up, end_sv.getX()), c.subvoxelsToVoxels(.border_up, end_sv.x),
c.subvoxelsToVoxelSubvoxels(end_sv.getX()), c.subvoxelsToVoxelSubvoxels(end_sv.x),
c.subvoxelsToVoxels(.border_up, end_sv.getY()), c.subvoxelsToVoxels(.border_up, end_sv.y),
c.subvoxelsToVoxelSubvoxels(end_sv.getY()), c.subvoxelsToVoxelSubvoxels(end_sv.y),
c.subvoxelsToVoxels(.border_up, end_sv.getZ()), c.subvoxelsToVoxels(.border_up, end_sv.z),
c.subvoxelsToVoxelSubvoxels(end_sv.getZ()), c.subvoxelsToVoxelSubvoxels(end_sv.z),
}); });
const zero = Vector3Int.zero.vector; const zero = vm.epi32(0);
const one = Vector3Int.one.vector; const one = vm.epi32(1);
const ray_positive: Vector3Int = .{ .vector = @select(i32, ray_sv.vector > zero, one, zero) }; const ray_positive: vm.Vector3Int = .{ .vector = @select(i32, ray_sv.vector > zero, one, zero) };
const ray_negative: Vector3Int = .{ .vector = @select(i32, ray_sv.vector < zero, one, zero) }; const ray_negative: vm.Vector3Int = .{ .vector = @select(i32, ray_sv.vector < zero, one, zero) };
const ray_sign: Vector3Int = .sub(ray_positive, ray_negative); const ray_sign: vm.Vector3Int = .sub(ray_positive, ray_negative);
const start_vx = origin_sv.sub(ray_positive).divScalar(c.sv_per_vx).add(ray_sign); const start_vx = origin_sv.sub(ray_positive).divScalar(c.sv_per_vx).add(ray_sign);
const end_vx = end_sv.sub(ray_positive).divScalar(c.sv_per_vx); const end_vx = end_sv.sub(ray_positive).divScalar(c.sv_per_vx);
const abs_ray_sv = ray_sv.abs(); const abs_ray_sv = ray_sv.abs();
std.debug.print("Start [VX]: ({d}, {d}, {d}) | End [VX]: ({d}, {d}, {d})\n", .{ std.debug.print("Start [VX]: ({d}, {d}, {d}) | End [VX]: ({d}, {d}, {d})\n", .{
start_vx.getX(), start_vx.x,
start_vx.getY(), start_vx.y,
start_vx.getZ(), start_vx.z,
end_vx.getX(), end_vx.x,
end_vx.getY(), end_vx.y,
end_vx.getZ(), end_vx.z,
}); });
var i_index: usize = undefined; var i_index: usize = undefined;
var j_index: usize = undefined; var j_index: usize = undefined;
var k_index: usize = undefined; var k_index: usize = undefined;
if (abs_ray_sv.getX() > abs_ray_sv.getY() and abs_ray_sv.getX() > abs_ray_sv.getZ()) { if (abs_ray_sv.x > abs_ray_sv.y and abs_ray_sv.x > abs_ray_sv.z) {
// Main axis: ±X // Main axis: ±X
i_index, j_index, k_index = .{ 0, 1, 2 }; i_index, j_index, k_index = .{ 0, 1, 2 };
std.debug.print("Order is (X, Y, Z)\n", .{}); std.debug.print("Order is (X, Y, Z)\n", .{});
} else if (abs_ray_sv.getY() > abs_ray_sv.getZ()) { } else if (abs_ray_sv.y > abs_ray_sv.z) {
// Main axis: ±Y // Main axis: ±Y
i_index, j_index, k_index = .{ 1, 2, 0 }; i_index, j_index, k_index = .{ 1, 2, 0 };
std.debug.print("Order is (Y, Z, X)\n", .{}); std.debug.print("Order is (Y, Z, X)\n", .{});
} else if (abs_ray_sv.getZ() > 0) { } else if (abs_ray_sv.z > 0) {
// Main axis: ±Z // Main axis: ±Z
i_index, j_index, k_index = .{ 2, 0, 1 }; i_index, j_index, k_index = .{ 2, 0, 1 };
std.debug.print("Order is (Z, X, Y)\n", .{}); std.debug.print("Order is (Z, X, Y)\n", .{});
} else { } else {
std.debug.assert(abs_ray_sv.getX() == 0); std.debug.assert(abs_ray_sv.x == 0);
std.debug.assert(abs_ray_sv.getY() == 0); std.debug.assert(abs_ray_sv.y == 0);
std.debug.assert(abs_ray_sv.getZ() == 0); std.debug.assert(abs_ray_sv.z == 0);
return null; return null;
} }

View File

@@ -6,6 +6,7 @@ const glfw = @import("zglfw");
const math = @import("math.zig"); const math = @import("math.zig");
const shaders = @import("shaders.zig"); const shaders = @import("shaders.zig");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vm = @import("vecmath");
const worldgen = @import("worldgen.zig"); const worldgen = @import("worldgen.zig");
const Blocks = @import("assets/Blocks.zig"); const Blocks = @import("assets/Blocks.zig");
@@ -15,17 +16,11 @@ const CommandBuffer = @import("engine/CommandBuffer.zig");
const Engine = @import("engine/Engine.zig"); const Engine = @import("engine/Engine.zig");
const Iterator2 = math.Iterator2; const Iterator2 = math.Iterator2;
const Materials = @import("assets/Materials.zig"); const Materials = @import("assets/Materials.zig");
const Matrix4x4 = math.Matrix4x4;
const Player = @import("Player.zig"); const Player = @import("Player.zig");
const Quaternion = math.Quaternion;
const Skybox = @import("engine/Skybox.zig"); const Skybox = @import("engine/Skybox.zig");
const StagingBuffer = @import("engine/StagingBuffer.zig"); const StagingBuffer = @import("engine/StagingBuffer.zig");
const Swapchain = @import("engine/Swapchain.zig"); const Swapchain = @import("engine/Swapchain.zig");
const Textures = @import("assets/Textures.zig"); const Textures = @import("assets/Textures.zig");
const Vector2 = math.Vector2;
const Vector2x8 = math.Vector2x8;
const Vector3 = math.Vector3;
const Vector3Int = math.Vector3Int;
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
engine: *Engine, engine: *Engine,
@@ -545,7 +540,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
while (it.next()) |chunk_coords2| { while (it.next()) |chunk_coords2| {
const chunk_coords3 = chunk_coords2 ++ [_]i16{0}; const chunk_coords3 = chunk_coords2 ++ [_]i16{0};
const origin = Vector3.init( const origin = vm.Vector3.init(
@floatFromInt(chunk_coords3[0]), @floatFromInt(chunk_coords3[0]),
@floatFromInt(chunk_coords3[1]), @floatFromInt(chunk_coords3[1]),
@floatFromInt(chunk_coords3[2]), @floatFromInt(chunk_coords3[2]),
@@ -564,14 +559,14 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
var y: usize = 0; var y: usize = 0;
while (y < 16) : (y += 1) { while (y < 16) : (y += 1) {
const fpos0 = Vector2x8.initScalars( const fpos0 = vm.Vector2x8.init(
.{ 0, 1, 2, 3, 4, 5, 6, 7 }, .{ 0, 1, 2, 3, 4, 5, 6, 7 },
@splat(@floatFromInt(y)), @splat(@floatFromInt(y)),
).add(.initVector(origin.asVector2())); ).add(.splat(origin.dropZ()));
const fpos1 = Vector2x8.initScalars( const fpos1 = vm.Vector2x8.init(
.{ 8, 9, 10, 11, 12, 13, 14, 15 }, .{ 8, 9, 10, 11, 12, 13, 14, 15 },
@splat(@floatFromInt(y)), @splat(@floatFromInt(y)),
).add(.initVector(origin.asVector2())); ).add(.splat(origin.dropZ()));
const iheight0 = worldgen.heightIv(world_seed, fpos0); const iheight0 = worldgen.heightIv(world_seed, fpos0);
const iheight1 = worldgen.heightIv(world_seed, fpos1); const iheight1 = worldgen.heightIv(world_seed, fpos1);
@@ -596,7 +591,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
} }
} }
const player_position_vx = Vector3Int.init(0, 0, worldgen.heightI(world_seed, .zero) + 1); const player_position_vx = vm.Vector3Int.init(0, 0, worldgen.heightI(world_seed, .zero) + 1);
const player_position_sv = player_position_vx const player_position_sv = player_position_vx
.mulScalar(c.sv_per_vx) .mulScalar(c.sv_per_vx)
.add(.init(c.sv_per_vx / 2, c.sv_per_vx / 2, 0)); .add(.init(c.sv_per_vx / 2, c.sv_per_vx / 2, 0));
@@ -623,8 +618,8 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
const directional_lights_data: []const shaders.DirectionalLight = &.{ const directional_lights_data: []const shaders.DirectionalLight = &.{
.{ .{
.directionWS = .{ 0, 0, -1 }, .directionWS = .unit_nz,
.color = .{ 0.3, 0.3, 0.3 }, .color = .init(0.3, 0.3, 0.3),
}, },
}; };
try directional_lights.write(engine, .{ try directional_lights.write(engine, .{
@@ -765,30 +760,33 @@ fn render(self: *Game) !void {
const extent = self.swapchain.extent; const extent = self.swapchain.extent;
const framebuffer_size = Vector2.init( const framebuffer_size = vm.Vector2.init(
@floatFromInt(extent.width), @floatFromInt(extent.width),
@floatFromInt(extent.height), @floatFromInt(extent.height),
); );
const camera_position = self.player.position_sv const camera_position = vm.Vector3.init(
.asVector3() @floatFromInt(self.player.position_sv.x),
@floatFromInt(self.player.position_sv.y),
@floatFromInt(self.player.position_sv.z),
)
.divScalar(c.sv_per_vx) .divScalar(c.sv_per_vx)
.add(.init(0, 0, Player.camera_height_vx)); .add(.init(0, 0, Player.camera_height_vx));
const camera_rotation = Quaternion.mulQuaternion( const camera_rotation = vm.Quaternion.mulQuaternion(
.initRotationXY(self.player.yaw_rad), .initRotation(.XY, self.player.yaw_turns),
.initRotationYZ(self.player.pitch_rad), .initRotation(.YZ, self.player.pitch_turns),
); );
const camera_aspect_ratio = framebuffer_size.getX() / framebuffer_size.getY(); const camera_aspect_ratio = framebuffer_size.x / framebuffer_size.y;
const camera_yscale = 1.0 / @tan(0.5 * self.player.vertical_fov_deg * std.math.rad_per_deg); const camera_yscale = 1.0 / @tan(0.5 * self.player.vertical_fov_deg * std.math.rad_per_deg);
const camera_xscale = camera_yscale / camera_aspect_ratio; const camera_xscale = camera_yscale / camera_aspect_ratio;
const matrix_ws_to_vs = Matrix4x4.mulMatrix( const matrix_ws_to_vs = vm.Matrix4x4.mulMatrixAffine(
Matrix4x4.initRotation(camera_rotation.conjugate()), .initRotation(camera_rotation.inverseUnit()),
Matrix4x4.initTranslation(camera_position.negate()), .initTranslation(camera_position.negate()),
); );
// zig fmt: off // zig fmt: off
const matrix_vs_to_cs = Matrix4x4.init( const matrix_vs_to_cs = vm.Matrix4x4.init(
camera_xscale, 0, 0, 0, camera_xscale, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 1,
0, -camera_yscale, 0, 0, 0, -camera_yscale, 0, 0,
@@ -796,12 +794,12 @@ fn render(self: *Game) !void {
); );
// zig fmt: on // zig fmt: on
const ambient_light = Vector3.init(0.01, 0.01, 0.01); const ambient_light = vm.Vector3.init(0.01, 0.01, 0.01);
const global_uniforms_data: shaders.GlobalUniforms = .{ const global_uniforms_data: shaders.GlobalUniforms = .{
.matrixWStoVS = matrix_ws_to_vs.asArray(), .matrixWStoVS = matrix_ws_to_vs,
.matrixVStoCS = matrix_vs_to_cs.asArray(), .matrixVStoCS = matrix_vs_to_cs,
.ambientLight = ambient_light.asArray(), .ambientLight = ambient_light,
}; };
const staging_memory = try self.global_uniforms_staging_buffer.map(self.engine); const staging_memory = try self.global_uniforms_staging_buffer.map(self.engine);

View File

@@ -4,15 +4,11 @@ const std = @import("std");
const c = @import("const.zig"); const c = @import("const.zig");
const glfw = @import("zglfw"); const glfw = @import("zglfw");
const math = @import("math.zig"); const math = @import("math.zig");
const vm = @import("vecmath");
const Blocks = @import("assets/Blocks.zig"); const Blocks = @import("assets/Blocks.zig");
const Chunks = @import("Chunks.zig"); const Chunks = @import("Chunks.zig");
const Iterator2 = math.Iterator2; const Iterator2 = math.Iterator2;
const Quaternion = math.Quaternion;
const Vector2 = math.Vector2;
const Vector3 = math.Vector3;
const Vector2Int = math.Vector2Int;
const Vector3Int = math.Vector3Int;
const AxisState = enum { const AxisState = enum {
none, none,
@@ -157,25 +153,25 @@ const Button = struct {
const MovementState = union(enum) { const MovementState = union(enum) {
ground: struct { ground: struct {
horizontal_velocity_sv: Vector2Int, horizontal_velocity_sv: vm.Vector2Int,
}, },
air: struct { air: struct {
horizontal_velocity_sv: Vector2Int, horizontal_velocity_sv: vm.Vector2Int,
vertical_velocity_sv: i32, vertical_velocity_sv: i32,
}, },
flight: void, flight: void,
}; };
position_sv: Vector3Int, position_sv: vm.Vector3Int,
pitch_rad: f32, pitch_turns: f32,
yaw_rad: f32, yaw_turns: f32,
x_input: Axis = .init(.d, .a), x_input: Axis = .init(.d, .a),
y_input: Axis = .init(.w, .s), y_input: Axis = .init(.w, .s),
z_input: Axis = .init(.space, .left_shift), z_input: Axis = .init(.space, .left_shift),
jump_input: Button = .init(.space), jump_input: Button = .init(.space),
mouse_sensitivity: f32 = 0.002, mouse_sensitivity: f32 = 0.0003,
vertical_fov_deg: f32 = 80, vertical_fov_deg: f32 = 80,
movement_state: MovementState, movement_state: MovementState,
@@ -185,8 +181,8 @@ pub const camera_height_vx = 1.62;
pub const horizontal_speed_sv = sv(11.0); pub const horizontal_speed_sv = sv(11.0);
pub const vertical_speed_sv = sv(7.49); pub const vertical_speed_sv = sv(7.49);
pub const min_pitch_rad = -0.5 * std.math.pi; pub const min_pitch_turns = -0.25;
pub const max_pitch_rad = 0.5 * std.math.pi; pub const max_pitch_turns = 0.25;
pub const collision_half_width_sv = sv(0.4); pub const collision_half_width_sv = sv(0.4);
pub const collision_height_sv = sv(1.8); pub const collision_height_sv = sv(1.8);
@@ -203,11 +199,11 @@ pub const air_speed_limit_sv = sv(0.5612);
pub const raycast_length_sv = sv(5.0); pub const raycast_length_sv = sv(5.0);
pub fn init(position_sv: Vector3Int, pitch_rad: f32, yaw_rad: f32) Player { pub fn init(position_sv: vm.Vector3Int, pitch_turns: f32, yaw_turns: f32) Player {
return .{ return .{
.position_sv = position_sv, .position_sv = position_sv,
.pitch_rad = pitch_rad, .pitch_turns = pitch_turns,
.yaw_rad = yaw_rad, .yaw_turns = yaw_turns,
.movement_state = .flight, .movement_state = .flight,
}; };
} }
@@ -225,8 +221,8 @@ pub fn onKeyUp(self: *Player, key: glfw.Key) void {
} }
pub fn onMouseMove(self: *Player, dx: f32, dy: f32) void { pub fn onMouseMove(self: *Player, dx: f32, dy: f32) void {
self.pitch_rad = std.math.clamp(self.pitch_rad - dy * self.mouse_sensitivity, min_pitch_rad, max_pitch_rad); self.pitch_turns = std.math.clamp(self.pitch_turns - dy * self.mouse_sensitivity, min_pitch_turns, max_pitch_turns);
self.yaw_rad = @mod(self.yaw_rad - dx * self.mouse_sensitivity, std.math.tau); self.yaw_turns = @mod(self.yaw_turns - dx * self.mouse_sensitivity, 1);
} }
pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void { pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
@@ -234,11 +230,11 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
//const raycast_origin_sv = self.position_sv //const raycast_origin_sv = self.position_sv
// .add(.init(0, 0, @intFromFloat(@round(c.sv_per_vx * camera_height_vx)))); // .add(.init(0, 0, @intFromFloat(@round(c.sv_per_vx * camera_height_vx))));
//const raycast_ray_sv = Vector3 //const raycast_ray_sv = vm.Vector3
// .init(0, raycast_length_sv, 0) // .init(0, raycast_length_sv, 0)
// .rotate(.mulQuaternion( // .rotate(.mulQuaternion(
// .initRotationXY(self.yaw_rad), // .initRotation(.XY, self.yaw_turns),
// .initRotationYZ(self.pitch_rad), // .initRotation(.YZ, self.pitch_turns),
// )) // ))
// .asVector3Int(); // .asVector3Int();
//const raycast_hit = chunks.raycast(raycast_origin_sv, raycast_ray_sv); //const raycast_hit = chunks.raycast(raycast_origin_sv, raycast_ray_sv);
@@ -246,14 +242,14 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
// --- GATHER INPUTS ------------------------------------------------------- // --- GATHER INPUTS -------------------------------------------------------
const horizontal_input_vector_frac = blk: { const horizontal_input_vector_frac = blk: {
var ret = Vector2 var ret = vm.Vector2
.init(self.x_input.getComponentFloat(), self.y_input.getComponentFloat()) .init(self.x_input.getComponentFloat(), self.y_input.getComponentFloat())
.rotate(self.yaw_rad); .rotate(.initRotation(self.yaw_turns));
const len_squared = ret.lenSquared(); const len_squared = ret.lenSquared();
if (len_squared > 1) { if (len_squared > 1) {
ret = ret.divScalar(@sqrt(len_squared)); ret = ret.divScalar(@sqrt(len_squared));
} }
break :blk ret.asVector2IntFrac(); break :blk math.asIntFrac2(ret);
}; };
const vertical_input_vector_frac = self.z_input.getComponentIntFrac(); const vertical_input_vector_frac = self.z_input.getComponentIntFrac();
@@ -279,10 +275,10 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
.ground => {}, .ground => {},
.air => {}, .air => {},
.flight => { .flight => {
const horizontal_velocity_sv = horizontal_input_vector_frac.mulScalarFrac(horizontal_speed_sv); const horizontal_velocity_sv = math.mulFrac2(horizontal_input_vector_frac, horizontal_speed_sv);
const vertical_velocity_sv = math.mulFrac(vertical_input_vector_frac, vertical_speed_sv); const vertical_velocity_sv = math.mulFrac(vertical_input_vector_frac, vertical_speed_sv);
var horizontal_displacement_sv = horizontal_velocity_sv.mulScalarFloat(dt); var horizontal_displacement_sv = math.mulIntFloat2(horizontal_velocity_sv, dt);
var vertical_displacement_sv = math.mulIntFloat(vertical_velocity_sv, dt); var vertical_displacement_sv = math.mulIntFloat(vertical_velocity_sv, dt);
var position_sv = self.position_sv; var position_sv = self.position_sv;
@@ -301,9 +297,7 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
var i: usize = 0; var i: usize = 0;
while (i < 2) : (i += 1) { while (i < 2) : (i += 1) {
if (chunks.sweepCastHorizontal(min_sv, max_sv, horizontal_displacement_sv)) |hit| { if (chunks.sweepCastHorizontal(min_sv, max_sv, horizontal_displacement_sv)) |hit| {
const adjustment = hit.normal_frac const adjustment = math.mulFrac2(hit.normal_frac.dropZ(), hit.projected_distance_sv);
.asVector2Int()
.mulScalarFrac(hit.projected_distance_sv);
horizontal_displacement_sv = .add( horizontal_displacement_sv = .add(
horizontal_displacement_sv, horizontal_displacement_sv,
adjustment, adjustment,
@@ -312,11 +306,11 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
break; break;
} }
} }
position_sv = .add(position_sv, horizontal_displacement_sv.asVector3Int(0)); position_sv = .add(position_sv, horizontal_displacement_sv.withZ(0));
if (vertical_displacement_sv < 0.0) { if (vertical_displacement_sv < 0.0) {
min_sv = .add(min_sv, horizontal_displacement_sv.asVector3Int(0)); min_sv = .add(min_sv, horizontal_displacement_sv.withZ(0));
max_sv = .add(max_sv, horizontal_displacement_sv.asVector3Int(0)); max_sv = .add(max_sv, horizontal_displacement_sv.withZ(0));
if (chunks.sweepCastDown(min_sv, max_sv, -vertical_displacement_sv)) |hit| { if (chunks.sweepCastDown(min_sv, max_sv, -vertical_displacement_sv)) |hit| {
vertical_displacement_sv += hit.projected_distance_sv; vertical_displacement_sv += hit.projected_distance_sv;
} }

View File

@@ -4,6 +4,7 @@ const std = @import("std");
const math = @import("../math.zig"); const math = @import("../math.zig");
const shaders = @import("../shaders.zig"); const shaders = @import("../shaders.zig");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vm = @import("vecmath");
const voxels = @import("../voxels.zig"); const voxels = @import("../voxels.zig");
const Blocks = @import("Blocks.zig"); const Blocks = @import("Blocks.zig");
@@ -13,9 +14,7 @@ const Game = @import("../Game.zig");
const GenericBuffer = @import("../engine/GenericBuffer.zig").GenericBuffer; const GenericBuffer = @import("../engine/GenericBuffer.zig").GenericBuffer;
const Materials = @import("Materials.zig"); const Materials = @import("Materials.zig");
const Matrix4x4 = math.Matrix4x4;
const ObjectUniformsBuffer = GenericBuffer(void, shaders.ObjectUniforms); const ObjectUniformsBuffer = GenericBuffer(void, shaders.ObjectUniforms);
const Vector3 = math.Vector3;
pub const chunk_size = 16; pub const chunk_size = 16;
@@ -25,7 +24,7 @@ var next_chunk_id: std.atomic.Value(u64) = .init(0);
/// To get the block at coordinates (x, y, z) relative to the chunk, read the /// To get the block at coordinates (x, y, z) relative to the chunk, read the
/// value at `blocks[z][y][x]`. /// value at `blocks[z][y][x]`.
blocks: [chunk_size][chunk_size][chunk_size]Blocks.Id, blocks: [chunk_size][chunk_size][chunk_size]Blocks.Id,
origin: Vector3, origin: vm.Vector3,
descriptor_set: vk.DescriptorSet, descriptor_set: vk.DescriptorSet,
object_buffer: ObjectUniformsBuffer, object_buffer: ObjectUniformsBuffer,
object_count: u32, object_count: u32,
@@ -34,7 +33,7 @@ object_count: u32,
chunk_id: u64, chunk_id: u64,
pub const InitInfo = struct { pub const InitInfo = struct {
origin: Vector3, origin: vm.Vector3,
descriptor_pool: vk.DescriptorPool, descriptor_pool: vk.DescriptorPool,
per_batch_descriptor_set_layout: vk.DescriptorSetLayout, per_batch_descriptor_set_layout: vk.DescriptorSetLayout,
}; };
@@ -110,14 +109,18 @@ pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors:
for (row, 0..) |id, ix| { for (row, 0..) |id, ix| {
const fx: f32 = @floatFromInt(ix); const fx: f32 = @floatFromInt(ix);
const block: *const Blocks.Definition = &blocks.array.items[id.toInt()]; const block: *const Blocks.Definition = &blocks.array.items[id.toInt()];
const origin = Vector3.add(self.origin, .init(fx, fy, fz)); const origin = vm.Vector3.add(self.origin, .init(fx, fy, fz));
inline for (@typeInfo(voxels.Orientation).@"enum".fields) |field| { inline for (@typeInfo(voxels.Orientation).@"enum".fields) |field| {
const side = @field(voxels.Orientation, field.name); const side = @field(voxels.Orientation, field.name);
const material = @field(block.walls, field.name).material; const material = @field(block.walls, field.name).material;
if (material != .empty and self.getOpposite(side, ix, iy, iz, blocks, neighbors) == .empty) { if (material != .empty and self.getOpposite(side, ix, iy, iz, blocks, neighbors) == .empty) {
const matrix = getMatrix(side, origin); const matrix = getMatrix(side, origin);
try uniforms.append(temp_allocator, .init(matrix, matrix, material)); try uniforms.append(temp_allocator, .{
.matrixOStoWS = matrix,
.matrixOStoWSNormal = matrix,
.material = material,
});
} }
} }
} }
@@ -209,44 +212,44 @@ fn getOpposite(self: *const Chunk, comptime side: voxels.Orientation, x: usize,
}; };
} }
fn getMatrix(comptime side: voxels.Orientation, origin: Vector3) Matrix4x4 { fn getMatrix(comptime side: voxels.Orientation, origin: vm.Vector3) vm.Matrix4x4 {
return switch (side) { return switch (side) {
// zig fmt: off // zig fmt: off
.positive_x => .init( .positive_x => .init(
0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0,
origin.getX() + 1, origin.getY(), origin.getZ(), 1, origin.x + 1, origin.y, origin.z, 1,
), ),
.negative_x => .init( .negative_x => .init(
0, -1, 0, 0, 0, -1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
-1, 0, 0, 0, -1, 0, 0, 0,
origin.getX(), origin.getY() + 1, origin.getZ(), 1, origin.x, origin.y + 1, origin.z, 1,
), ),
.positive_y => .init( .positive_y => .init(
-1, 0, 0, 0, -1, 0, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 1, 0, 0,
origin.getX() + 1, origin.getY() + 1, origin.getZ(), 1, origin.x + 1, origin.y + 1, origin.z, 1,
), ),
.negative_y => .init( .negative_y => .init(
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, -1, 0, 0, 0, -1, 0, 0,
origin.getX(), origin.getY(), origin.getZ(), 1, origin.x, origin.y, origin.z, 1,
), ),
.positive_z => .init( .positive_z => .init(
1, 0, 0, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
origin.getX(), origin.getY(), origin.getZ() + 1, 1, origin.x, origin.y, origin.z + 1, 1,
), ),
.negative_z => .init( .negative_z => .init(
1, 0, 0, 0, -1, 0, 0, 0,
0, -1, 0, 0, 0, -1, 0, 0,
0, 0, -1, 0, 0, 0, 1, 0,
origin.getX() + 1, origin.getY() + 1, origin.getZ(), 1, origin.x + 1, origin.y + 1, origin.z, 1,
), ),
// zig fmt: on // zig fmt: on
}; };

View File

@@ -80,8 +80,8 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Materials {
.element_offset = Id.empty.toInt(), .element_offset = Id.empty.toInt(),
.elements = &.{ .elements = &.{
.{ .{
.base_color = .{ 0, 0, 0 }, .base_color = .zero,
.emissive = .{ 1, 0, 1 }, .emissive = .init(1, 0, 1),
.ior = 1.45, .ior = 1.45,
.metallic = 0, .metallic = 0,
.normal_scale = 1, .normal_scale = 1,
@@ -295,8 +295,8 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, filename
.element_offset = index, .element_offset = index,
.elements = &.{ .elements = &.{
.{ .{
.base_color = material_json.baseColor, .base_color = .initArray(material_json.baseColor),
.emissive = material_json.emissive, .emissive = .initArray(material_json.emissive),
.ior = material_json.ior, .ior = material_json.ior,
.metallic = material_json.metallic, .metallic = material_json.metallic,
.normal_scale = material_json.normalScale, .normal_scale = material_json.normalScale,

View File

@@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
const vm = @import("vecmath");
const Vector2Int = @import("math.zig").Vector2Int;
pub const app_name = "voxel-game"; pub const app_name = "voxel-game";
pub const app_version_string = @import("config").version; pub const app_version_string = @import("config").version;
@@ -11,11 +10,11 @@ pub const max_frametime = 1.0 / min_framerate;
pub const default_window_width = 1280; pub const default_window_width = 1280;
pub const default_window_height = 720; pub const default_window_height = 720;
pub const default_window_size = Vector2Int.init(default_window_width, default_window_height); pub const default_window_size = vm.Vector2Int.init(default_window_width, default_window_height);
pub const min_window_width = 640; pub const min_window_width = 640;
pub const min_window_height = 360; pub const min_window_height = 360;
pub const min_window_size = Vector2Int.init(default_window_width, default_window_height); pub const min_window_size = vm.Vector2Int.init(default_window_width, default_window_height);
pub const window_title = "Voxel Game"; pub const window_title = "Voxel Game";

View File

@@ -4,6 +4,7 @@ const std = @import("std");
const shaders = @import("../shaders.zig"); const shaders = @import("../shaders.zig");
const stbi = @import("zstbi"); const stbi = @import("zstbi");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vm = @import("vecmath");
const CommandBuffer = @import("CommandBuffer.zig"); const CommandBuffer = @import("CommandBuffer.zig");
const Engine = @import("Engine.zig"); const Engine = @import("Engine.zig");
@@ -14,7 +15,7 @@ image: vk.Image,
image_view: vk.ImageView, image_view: vk.ImageView,
device_memory: vk.DeviceMemory, device_memory: vk.DeviceMemory,
vertex_buffer: GenericBuffer(void, [3]f32), vertex_buffer: GenericBuffer(void, vm.Vector3),
index_buffer: shaders.IndexBuffer, index_buffer: shaders.IndexBuffer,
sampler: vk.Sampler, sampler: vk.Sampler,
@@ -468,7 +469,7 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_unifor
// --- SKYBOX PIPELINE ----------------------------------------------------- // --- SKYBOX PIPELINE -----------------------------------------------------
var vertex_buffer = try GenericBuffer(void, [3]f32).init(engine, .{ var vertex_buffer = try GenericBuffer(void, vm.Vector3).init(engine, .{
.usage = .vertex, .usage = .vertex,
.target_queue = .graphics, .target_queue = .graphics,
.array_capacity = 8, .array_capacity = 8,
@@ -485,14 +486,14 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_unifor
try vertex_buffer.write(engine, .{ try vertex_buffer.write(engine, .{
.elements = &.{ .elements = &.{
.{ -1, -1, -1 }, .init(-1, -1, -1),
.{ 1, -1, -1 }, .init(1, -1, -1),
.{ -1, 1, -1 }, .init(-1, 1, -1),
.{ 1, 1, -1 }, .init(1, 1, -1),
.{ -1, -1, 1 }, .init(-1, -1, 1),
.{ 1, -1, 1 }, .init(1, -1, 1),
.{ -1, 1, 1 }, .init(-1, 1, 1),
.{ 1, 1, 1 }, .init(1, 1, 1),
}, },
}); });

View File

@@ -1,41 +1,8 @@
const std = @import("std"); const std = @import("std");
const vm = @import("vecmath");
pub const Iterator2 = @import("math/Iterator2.zig").Iterator2; pub const Iterator2 = @import("math/Iterator2.zig").Iterator2;
pub const Iterator3 = @import("math/Iterator3.zig").Iterator3; pub const Iterator3 = @import("math/Iterator3.zig").Iterator3;
pub const Matrix4x4 = @import("math/Matrix4x4.zig").Matrix4x4;
pub const Quaternion = @import("math/Quaternion.zig").Quaternion;
pub const Vector2 = @import("math/Vector2.zig").Vector2;
pub const Vector2Int = @import("math/Vector2Int.zig").Vector2Int;
pub const Vector2x8 = @import("math/Vector2x8.zig").Vector2x8;
pub const Vector3 = @import("math/Vector3.zig").Vector3;
pub const Vector3Int = @import("math/Vector3Int.zig").Vector3Int;
pub const Vector4 = @import("math/Vector4.zig").Vector4;
pub const f32x8 = @Vector(8, f32);
pub const i32x8 = @Vector(8, i32);
pub const u32x8 = @Vector(8, u32);
pub const u64x8 = @Vector(8, u64);
pub inline fn ps(value: f32) f32x8 {
return @splat(value);
}
pub inline fn epi32(value: i32) i32x8 {
return @splat(value);
}
pub inline fn epu32(value: u32) u32x8 {
return @splat(value);
}
pub inline fn epu64x2(value: u64) u64x8 {
return @splat(value);
}
pub inline fn lerp(a: f32, b: f32, t: f32) f32 {
const s = 1.0 - t;
return a * s + b * t;
}
pub const noise2 = @import("math/noise.zig").noise2; pub const noise2 = @import("math/noise.zig").noise2;
pub const noise2x8 = @import("math/noise.zig").noise2x8; pub const noise2x8 = @import("math/noise.zig").noise2x8;
@@ -46,18 +13,90 @@ pub inline fn asFloatFrac(frac: i32) f32 {
return @floatCast(numerator / denominator); return @floatCast(numerator / denominator);
} }
pub inline fn asFloatFrac2(frac: vm.Vector2Int) vm.Vector2 {
return .init(
asFloatFrac(frac.x),
asFloatFrac(frac.y),
);
}
pub inline fn asFloatFrac3(frac: vm.Vector3Int) vm.Vector3 {
return .init(
asFloatFrac(frac.x),
asFloatFrac(frac.y),
asFloatFrac(frac.z),
);
}
pub inline fn asFloatFrac4(frac: vm.Vector4Int) vm.Vector4 {
return .init(
asFloatFrac(frac.x),
asFloatFrac(frac.y),
asFloatFrac(frac.z),
asFloatFrac(frac.w),
);
}
pub inline fn asIntFrac(frac: f32) i32 { pub inline fn asIntFrac(frac: f32) i32 {
const fraction: f64 = @floatCast(frac); const fraction: f64 = @floatCast(frac);
const scale: f64 = std.math.maxInt(i32); const scale: f64 = std.math.maxInt(i32);
return @intFromFloat(@round(fraction * scale)); return @intFromFloat(@round(fraction * scale));
} }
pub inline fn asIntFrac2(frac: vm.Vector2) vm.Vector2Int {
return .init(
asIntFrac(frac.x),
asIntFrac(frac.y),
);
}
pub inline fn asIntFrac3(frac: vm.Vector3) vm.Vector3Int {
return .init(
asIntFrac(frac.x),
asIntFrac(frac.y),
asIntFrac(frac.z),
);
}
pub inline fn asIntFrac4(frac: vm.Vector4) vm.Vector4Int {
return .init(
asIntFrac(frac.x),
asIntFrac(frac.y),
asIntFrac(frac.z),
asIntFrac(frac.w),
);
}
pub inline fn mulIntFloat(int: i32, float: f32) i32 { pub inline fn mulIntFloat(int: i32, float: f32) i32 {
const int_float: f64 = @floatFromInt(int); const int_float: f64 = @floatFromInt(int);
const float_wide: f64 = @floatCast(float); const float_wide: f64 = @floatCast(float);
return @intFromFloat(@round(int_float * float_wide)); return @intFromFloat(@round(int_float * float_wide));
} }
pub inline fn mulIntFloat2(int: vm.Vector2Int, float: f32) vm.Vector2Int {
return .init(
mulIntFloat(int.x, float),
mulIntFloat(int.y, float),
);
}
pub inline fn mulIntFloat3(int: vm.Vector3Int, float: f32) vm.Vector3Int {
return .init(
mulIntFloat(int.x, float),
mulIntFloat(int.y, float),
mulIntFloat(int.z, float),
);
}
pub inline fn mulIntFloat4(int: vm.Vector4Int, float: f32) vm.Vector4Int {
return .init(
mulIntFloat(int.x, float),
mulIntFloat(int.y, float),
mulIntFloat(int.z, float),
mulIntFloat(int.w, float),
);
}
pub inline fn mulFrac(a: i32, b: i32) i32 { pub inline fn mulFrac(a: i32, b: i32) i32 {
const denominator: i64 = std.math.maxInt(i32); const denominator: i64 = std.math.maxInt(i32);
const rounding_bias: i64 = denominator >> 1; const rounding_bias: i64 = denominator >> 1;
@@ -66,6 +105,30 @@ pub inline fn mulFrac(a: i32, b: i32) i32 {
return @intCast(@divFloor(a_wide * b_wide + rounding_bias, denominator)); return @intCast(@divFloor(a_wide * b_wide + rounding_bias, denominator));
} }
pub inline fn mulFrac2(a: vm.Vector2Int, b: i32) vm.Vector2Int {
return .init(
mulFrac(a.x, b),
mulFrac(a.y, b),
);
}
pub inline fn mulFrac3(a: vm.Vector3Int, b: i32) vm.Vector3Int {
return .init(
mulFrac(a.x, b),
mulFrac(a.y, b),
mulFrac(a.z, b),
);
}
pub inline fn mulFrac4(a: vm.Vector4Int, b: i32) vm.Vector4Int {
return .init(
mulFrac(a.x, b),
mulFrac(a.y, b),
mulFrac(a.z, b),
mulFrac(a.w, b),
);
}
pub inline fn mulFracFrac(a: i32, b: i32) i32 { pub inline fn mulFracFrac(a: i32, b: i32) i32 {
const denominator: i64 = std.math.maxInt(i32) * std.math.maxInt(i32); const denominator: i64 = std.math.maxInt(i32) * std.math.maxInt(i32);
const rounding_bias: i64 = denominator >> 1; const rounding_bias: i64 = denominator >> 1;
@@ -74,6 +137,30 @@ pub inline fn mulFracFrac(a: i32, b: i32) i32 {
return .{ .vector = @intCast(@divFloor(a_wide * b_wide + rounding_bias, denominator)) }; return .{ .vector = @intCast(@divFloor(a_wide * b_wide + rounding_bias, denominator)) };
} }
pub inline fn mulFracFrac2(a: vm.Vector2Int, b: i32) vm.Vector2Int {
return .init(
mulFracFrac(a.x, b),
mulFracFrac(a.y, b),
);
}
pub inline fn mulFracFrac3(a: vm.Vector3Int, b: i32) vm.Vector3Int {
return .init(
mulFracFrac(a.x, b),
mulFracFrac(a.y, b),
mulFracFrac(a.z, b),
);
}
pub inline fn mulFracFrac4(a: vm.Vector4Int, b: i32) vm.Vector4Int {
return .init(
mulFracFrac(a.x, b),
mulFracFrac(a.y, b),
mulFracFrac(a.z, b),
mulFracFrac(a.w, b),
);
}
pub inline fn wideMulDivFloor(a: i32, mul: i32, div: i32) i32 { pub inline fn wideMulDivFloor(a: i32, mul: i32, div: i32) i32 {
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul), div)); return @intCast(@divFloor(@as(i64, a) * @as(i64, mul), div));
} }

View File

@@ -1,283 +0,0 @@
const Vector3 = @import("Vector3.zig").Vector3;
const Vector4 = @import("Vector4.zig").Vector4;
const Quaternion = @import("Quaternion.zig").Quaternion;
pub const Matrix4x4 = extern struct {
i: Vector4,
j: Vector4,
k: Vector4,
t: Vector4,
pub const identity = Matrix4x4.init(
// zig fmt: off
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
// zig fmt: on
);
// --- INIT ---
pub inline fn init(
// zig fmt: off
ix: f32, iy: f32, iz: f32, iw: f32,
jx: f32, jy: f32, jz: f32, jw: f32,
kx: f32, ky: f32, kz: f32, kw: f32,
tx: f32, ty: f32, tz: f32, tw: f32,
// zig fmt: on
) Matrix4x4 {
return .{
.i = .init(ix, iy, iz, iw),
.j = .init(jx, jy, jz, jw),
.k = .init(kx, ky, kz, kw),
.t = .init(tx, ty, tz, tw),
};
}
pub inline fn initArray(array: [16]f32) Matrix4x4 {
return .{
.i = .initArray(array[0..4].*),
.j = .initArray(array[4..8].*),
.k = .initArray(array[8..12].*),
.t = .initArray(array[12..16].*),
};
}
pub inline fn initVector4(i: Vector4, j: Vector4, k: Vector4, t: Vector4) Matrix4x4 {
return .{ .i = i, .j = j, .k = k, .t = t };
}
pub inline fn initTranslation(translation: Vector3) Matrix4x4 {
return .initVector4(
.unit_x,
.unit_y,
.unit_z,
translation.asVector4(1),
);
}
pub inline fn initRotation(rotation: Quaternion) Matrix4x4 {
const xx = rotation.vector.getX() * rotation.vector.getX();
const xy = rotation.vector.getX() * rotation.vector.getY();
const xz = rotation.vector.getX() * rotation.vector.getZ();
const xw = rotation.vector.getX() * rotation.vector.getW();
const yy = rotation.vector.getY() * rotation.vector.getY();
const yz = rotation.vector.getY() * rotation.vector.getZ();
const yw = rotation.vector.getY() * rotation.vector.getW();
const zz = rotation.vector.getZ() * rotation.vector.getZ();
const zw = rotation.vector.getZ() * rotation.vector.getW();
return .init(
// zig fmt: off
1 - 2 * (yy + zz), 2 * (xy + zw), 2 * (xz - yw), 0,
2 * (xy - zw), 1 - 2 * (xx + zz), 2 * (yz + xw), 0,
2 * (xz + yw), 2 * (yz - xw), 1 - 2 * (xx + yy), 0,
0, 0, 0, 1,
// zig fmt: on
);
}
pub inline fn initScale(scale: Vector3) Matrix4x4 {
return .init(
// zig fmt: off
scale.getX(), 0, 0, 0,
0, scale.getY(), 0, 0,
0, 0, scale.getZ(), 0,
0, 0, 0, 1,
// zig fmt: on
);
}
pub inline fn initTranslationRotationScale(
translation: Vector3,
rotation: Quaternion,
scale: Vector3,
) Matrix4x4 {
const xx = rotation.vector.getX() * rotation.vector.getX();
const xy = rotation.vector.getX() * rotation.vector.getY();
const xz = rotation.vector.getX() * rotation.vector.getZ();
const xw = rotation.vector.getX() * rotation.vector.getW();
const yy = rotation.vector.getY() * rotation.vector.getY();
const yz = rotation.vector.getY() * rotation.vector.getZ();
const yw = rotation.vector.getY() * rotation.vector.getW();
const zz = rotation.vector.getZ() * rotation.vector.getZ();
const zw = rotation.vector.getZ() * rotation.vector.getW();
const rotation_i = Vector4.init((1 - 2 * (yy + zz)), 2 * (xy + zw), 2 * (xz - yw), 0);
const rotation_j = Vector4.init(2 * (xy - zw), (1 - 2 * (xx + zz)), 2 * (yz + xw), 0);
const rotation_k = Vector4.init(2 * (xz + yw), 2 * (yz - xw), (1 - 2 * (xx + yy)), 0);
return .initVector4(
.mulScalar(rotation_i, scale.getX()),
.mulScalar(rotation_j, scale.getY()),
.mulScalar(rotation_k, scale.getZ()),
translation.asVector4(1),
);
}
// --- CONVERSION ---
pub inline fn asArray(self: Matrix4x4) [16]f32 {
return self.i.asArray() ++ self.j.asArray() ++ self.k.asArray() ++ self.t.asArray();
}
pub inline fn asVector4(self: Matrix4x4) [4]Vector4 {
return .{ self.i, self.j, self.k, self.t };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .initVector4(
.add(self.i, other.i),
.add(self.j, other.j),
.add(self.k, other.k),
.add(self.t, other.t),
);
}
pub inline fn sub(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .initVector4(
.sub(self.i, other.i),
.sub(self.j, other.j),
.sub(self.k, other.k),
.sub(self.t, other.t),
);
}
pub inline fn negate(self: Matrix4x4) Matrix4x4 {
return .initVector4(
.negate(self.i),
.negate(self.j),
.negate(self.k),
.negate(self.t),
);
}
pub inline fn mulScalar(self: Matrix4x4, scalar: f32) Matrix4x4 {
return .initVector4(
.mulScalar(self.i, scalar),
.mulScalar(self.j, scalar),
.mulScalar(self.k, scalar),
.mulScalar(self.t, scalar),
);
}
pub inline fn divScalar(self: Matrix4x4, scalar: f32) Matrix4x4 {
const inv_scalar = 1 / scalar;
return .initVector4(
.mulScalar(self.i, inv_scalar),
.mulScalar(self.j, inv_scalar),
.mulScalar(self.k, inv_scalar),
.mulScalar(self.t, inv_scalar),
);
}
// --- OTHER ---
pub inline fn mulMatrix(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .initVector4(
self.i.mulScalar(other.i.getX())
.add(self.j.mulScalar(other.i.getY()))
.add(self.k.mulScalar(other.i.getZ()))
.add(self.t.mulScalar(other.i.getW())),
self.i.mulScalar(other.j.getX())
.add(self.j.mulScalar(other.j.getY()))
.add(self.k.mulScalar(other.j.getZ()))
.add(self.t.mulScalar(other.j.getW())),
self.i.mulScalar(other.k.getX())
.add(self.j.mulScalar(other.k.getY()))
.add(self.k.mulScalar(other.k.getZ()))
.add(self.t.mulScalar(other.k.getW())),
self.i.mulScalar(other.t.getX())
.add(self.j.mulScalar(other.t.getY()))
.add(self.k.mulScalar(other.t.getZ()))
.add(self.t.mulScalar(other.t.getW())),
);
}
pub inline fn inverseAffine(self: Matrix4x4) Matrix4x4 {
// zig fmt: off
const det = self.i.getX() * self.j.getY() * self.k.getZ()
+ self.i.getY() * self.j.getZ() * self.k.getX()
+ self.i.getZ() * self.j.getX() * self.k.getY()
- self.i.getX() * self.j.getZ() * self.k.getY()
- self.i.getY() * self.j.getX() * self.k.getZ()
- self.i.getZ() * self.j.getY() * self.k.getX();
// zig fmt: on
const inv_det = 1 / det;
const i = Vector3.init(
self.j.getY() * self.k.getZ() - self.j.getZ() * self.k.getY(),
self.i.getZ() * self.k.getY() - self.i.getY() * self.k.getZ(),
self.i.getY() * self.j.getZ() - self.i.getZ() * self.j.getY(),
).mulScalar(inv_det);
const j = Vector3.init(
self.j.getZ() * self.k.getX() - self.j.getX() * self.k.getZ(),
self.i.getX() * self.k.getZ() - self.i.getZ() * self.k.getX(),
self.i.getZ() * self.j.getX() - self.i.getX() * self.j.getZ(),
).mulScalar(inv_det);
const k = Vector3.init(
self.j.getX() * self.k.getY() - self.j.getY() * self.k.getX(),
self.i.getY() * self.k.getX() - self.i.getX() * self.k.getY(),
self.i.getX() * self.j.getY() - self.i.getY() * self.j.getX(),
).mulScalar(inv_det);
const t = self.i.asVector3().mulScalar(self.t.getX())
.add(self.j.asVector3().mulScalar(self.t.getY()))
.add(self.k.asVector3().mulScalar(self.t.getZ()))
.negate();
return .initVector4(
i.asVector4(0),
j.asVector4(0),
k.asVector4(0),
t.asVector4(1),
);
}
pub inline fn inverseTransposeAffine(self: Matrix4x4) Matrix4x4 {
// zig fmt: off
const det = self.i.getX() * self.j.getY() * self.k.getZ()
+ self.i.getY() * self.j.getZ() * self.k.getX()
+ self.i.getZ() * self.j.getX() * self.k.getY()
- self.i.getX() * self.j.getZ() * self.k.getY()
- self.i.getY() * self.j.getX() * self.k.getZ()
- self.i.getZ() * self.j.getY() * self.k.getX();
// zig fmt: on
const inv_det = 1 / det;
const i = Vector3.init(
self.j.getY() * self.k.getZ() - self.j.getZ() * self.k.getY(),
self.j.getZ() * self.k.getX() - self.j.getX() * self.k.getZ(),
self.j.getX() * self.k.getY() - self.j.getY() * self.k.getX(),
).mulScalar(inv_det);
const j = Vector3.init(
self.i.getZ() * self.k.getY() - self.i.getY() * self.k.getZ(),
self.i.getX() * self.k.getZ() - self.i.getZ() * self.k.getX(),
self.i.getY() * self.k.getX() - self.i.getX() * self.k.getY(),
).mulScalar(inv_det);
const k = Vector3.init(
self.i.getY() * self.j.getZ() - self.i.getZ() * self.j.getY(),
self.i.getZ() * self.j.getX() - self.i.getX() * self.j.getZ(),
self.i.getX() * self.j.getY() - self.i.getY() * self.j.getX(),
).mulScalar(inv_det);
const t = self.i.asVector3().mulScalar(self.t.getX())
.add(self.j.asVector3().mulScalar(self.t.getY()))
.add(self.k.asVector3().mulScalar(self.t.getZ()))
.negate();
return .initVector4(
i.asVector4(0),
j.asVector4(0),
k.asVector4(0),
t.asVector4(1),
);
}
};

View File

@@ -1,155 +0,0 @@
const Vector3 = @import("Vector3.zig").Vector3;
const Vector4 = @import("Vector4.zig").Vector4;
pub const Quaternion = extern struct {
vector: Vector4,
pub const identity = Quaternion.init(0, 0, 0, 1);
// --- INIT ---
pub inline fn init(x: f32, y: f32, z: f32, w: f32) Quaternion {
return .{ .vector = .init(x, y, z, w) };
}
pub inline fn initArray(array: [4]f32) Quaternion {
return .{ .vector = .initArray(array) };
}
pub inline fn initVector4(vector: Vector4) Quaternion {
return .{ .vector = vector };
}
pub inline fn initRotationXY(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
const c = @cos(half_angle_rad);
const s = @sin(half_angle_rad);
return .init(0, 0, s, c);
}
pub inline fn initRotationXZ(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
const c = @cos(half_angle_rad);
const s = @sin(half_angle_rad);
return .init(0, -s, 0, c);
}
pub inline fn initRotationYX(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
const c = @cos(half_angle_rad);
const s = @sin(half_angle_rad);
return .init(0, 0, -s, c);
}
pub inline fn initRotationYZ(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
const c = @cos(half_angle_rad);
const s = @sin(half_angle_rad);
return .init(s, 0, 0, c);
}
pub inline fn initRotationZX(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
const c = @cos(half_angle_rad);
const s = @sin(half_angle_rad);
return .init(0, s, 0, c);
}
pub inline fn initRotationZY(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
const c = @cos(half_angle_rad);
const s = @sin(half_angle_rad);
return .init(-s, 0, 0, c);
}
// --- CONVERSION ---
pub inline fn asArray(self: Quaternion) [4]f32 {
return self.vector.vector;
}
pub inline fn asVector4(self: Quaternion) Vector4 {
return self.vector;
}
// --- ACCESSORS ---
pub inline fn getVector(self: Quaternion) Vector3 {
return self.vector.asVector3();
}
pub inline fn getScalar(self: Quaternion) f32 {
return self.vector.getW();
}
pub inline fn setVector(self: Quaternion, vector: Vector3) Quaternion {
return .{
.vector = .{
.vector = @shuffle(f32, self.vector.vector, vector.vector, .{ ~@as(i32, 0), ~@as(i32, 1), ~@as(i32, 2), 3 }),
},
};
}
pub inline fn setScalar(self: Quaternion, scalar: f32) Quaternion {
return .initVector4(self.vector.setW(scalar));
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Quaternion, other: Quaternion) Quaternion {
return .initVector4(.add(self.vector, other.vector));
}
pub inline fn sub(self: Quaternion, other: Quaternion) Quaternion {
return .initVector4(.sub(self.vector, other.vector));
}
pub inline fn negate(self: Quaternion) Quaternion {
return .initVector4(.negate(self.vector));
}
pub inline fn conjugate(self: Quaternion) Quaternion {
return .initVector4(.mul(self.vector, .init(-1, -1, -1, 1)));
}
pub inline fn mulScalar(self: Quaternion, scalar: f32) Quaternion {
return .initVector4(.mulScalar(self.vector, scalar));
}
pub inline fn divScalar(self: Quaternion, scalar: f32) Quaternion {
return .initVector4(.divScalar(self.vector, scalar));
}
// --- OTHER ---
pub inline fn len(self: Quaternion) f32 {
return self.vector.len();
}
pub inline fn lenSquared(self: Quaternion) f32 {
return self.vector.lenSquared();
}
pub inline fn normalize(self: Quaternion) Quaternion {
return .initVector4(.normalize(self.vector));
}
pub inline fn dot(self: Quaternion, other: Quaternion) f32 {
return Vector4.dot(self.vector, other.vector);
}
pub inline fn lerp(self: Quaternion, other: Quaternion, t: f32) Quaternion {
return .initVector4(.lerp(self.vector, other.vector, t));
}
pub inline fn mulQuaternion(self: Quaternion, other: Quaternion) Quaternion {
const x1, const y1, const z1, const w1 = self.vector.vector;
const x2, const y2, const z2, const w2 = other.vector.vector;
return .init(
w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2,
w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2,
w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2,
w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2,
);
}
};

View File

@@ -1,172 +0,0 @@
const std = @import("std");
const Vector2Int = @import("Vector2Int.zig").Vector2Int;
const Vector3 = @import("Vector3.zig").Vector3;
const Vector4 = @import("Vector3.zig").Vector4;
pub const Vector2 = extern struct {
vector: Vector,
pub const Vector = @Vector(2, f32);
pub const Array = [2]f32;
pub const Mask = enum(i32) { x = 0, y = 1 };
pub const zero = Vector2.initScalar(0);
pub const one = Vector2.initScalar(1);
pub const unit_x = Vector2.init(1, 0);
pub const unit_y = Vector2.init(0, 1);
pub const unit_nx = Vector2.init(-1, 0);
pub const unit_ny = Vector2.init(0, -1);
// --- INIT ---
pub inline fn initScalar(scalar: f32) Vector2 {
return .{ .vector = @splat(scalar) };
}
pub inline fn init(x: f32, y: f32) Vector2 {
return .{ .vector = .{ x, y } };
}
pub inline fn initArray(array: Array) Vector2 {
return .{ .vector = array };
}
// --- CONVERSION ---
pub inline fn asArray(self: Vector2) Array {
return self.vector;
}
pub inline fn asArrayNorm(self: Vector2, comptime T: type) [2]T {
const scale_vector: Vector = @splat(std.math.maxInt(T));
return @as(@Vector(2, T), @intFromFloat(@round(self.vector * scale_vector)));
}
pub inline fn asVector2Int(self: Vector2) Vector2Int {
return .{ .vector = @intFromFloat(@round(self.vector)) };
}
pub inline fn asVector2IntFrac(self: Vector2) Vector2Int {
const fraction: @Vector(2, f64) = @floatCast(self.vector);
const scale: @Vector(2, f64) = @splat(std.math.maxInt(i32));
return .{ .vector = @intFromFloat(@round(fraction * scale)) };
}
pub inline fn asVector3(self: Vector2, z: f32) Vector3 {
const z_vector: @Vector(3, f32) = .{ undefined, undefined, z };
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
}
pub inline fn asVector4(self: Vector4, z: f32, w: f32) Vector4 {
const zw_vector: @Vector(4, f32) = .{ undefined, undefined, z, w };
return .{ .vector = @shuffle(f32, self.vector, zw_vector, [_]i32{ 0, 1, ~@as(i32, 2), ~@as(i32, 3) }) };
}
// --- ACCESSORS ---
pub inline fn getX(self: Vector2) f32 {
return self.vector[0];
}
pub inline fn getY(self: Vector2) f32 {
return self.vector[1];
}
pub inline fn setX(self: Vector2, x: f32) Vector2 {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(f32, self.vector, x_vector, .{ ~@as(i32, 0), 1 }) };
}
pub inline fn setY(self: Vector2, y: f32) Vector2 {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(f32, self.vector, y_vector, .{ 0, ~@as(i32, 1) }) };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Vector2, other: Vector2) Vector2 {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector2, other: Vector2) Vector2 {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector2, other: Vector2) Vector2 {
return .{ .vector = self.vector * other.vector };
}
pub inline fn div(self: Vector2, other: Vector2) Vector2 {
return .{ .vector = self.vector / other.vector };
}
pub inline fn negate(self: Vector2) Vector2 {
return .{ .vector = -self.vector };
}
pub inline fn mulScalar(self: Vector2, scalar: f32) Vector2 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn divScalar(self: Vector2, scalar: f32) Vector2 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector / scalar_vector };
}
// --- SWIZZLE ---
pub inline fn swizzle2(self: Vector2, comptime mask: [2]Mask) Vector2 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
}
pub inline fn swizzle3(self: Vector2, comptime mask: [3]Mask) Vector3 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
}
pub inline fn swizzle4(self: Vector2, comptime mask: [4]Mask) Vector4 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([4]i32, @bitCast(mask))) };
}
// --- OTHER ---
pub inline fn len(self: Vector2) f32 {
return @sqrt(@reduce(.Add, self.vector * self.vector));
}
pub inline fn lenSquared(self: Vector2) f32 {
return @reduce(.Add, self.vector * self.vector);
}
pub inline fn normalize(self: Vector2) Vector2 {
const len_vector: Vector = @splat(@sqrt(@reduce(.Add, self.vector * self.vector)));
return .{ .vector = self.vector / len_vector };
}
pub inline fn dot(self: Vector2, other: Vector2) f32 {
return @reduce(.Add, self.vector * other.vector);
}
pub inline fn cross(self: Vector2, other: Vector2) f32 {
return self.getX() * other.getY() - self.getY() * other.getX();
}
pub inline fn lerp(self: Vector2, other: Vector2, t: f32) Vector2 {
const s = 1.0 - t;
const t_vector: Vector = @splat(t);
const s_vector: Vector = @splat(s);
return .{ .vector = self * s_vector + other * t_vector };
}
pub inline fn rotate(self: Vector2, angle_rad: f32) Vector2 {
const c = @cos(angle_rad);
const s = @sin(angle_rad);
return .{
.vector = .{
self.getX() * c - self.getY() * s,
self.getX() * s + self.getY() * c,
},
};
}
};

View File

@@ -1,199 +0,0 @@
const std = @import("std");
const Vector2 = @import("Vector2.zig").Vector2;
const Vector3Int = @import("Vector3Int.zig").Vector3Int;
pub const Vector2Int = extern struct {
vector: Vector,
pub const Vector = @Vector(2, i32);
pub const Array = [2]i32;
pub const Mask = enum(i32) { x = 0, y = 1 };
pub const zero = Vector2Int.initScalar(0);
pub const one = Vector2Int.initScalar(1);
pub const one_frac = Vector2Int.initScalar(std.math.maxInt(i32));
pub const unit_x = Vector2Int.init(1, 0);
pub const unit_y = Vector2Int.init(0, 1);
pub const unit_nx = Vector2Int.init(-1, 0);
pub const unit_ny = Vector2Int.init(0, -1);
pub const unit_x_frac = Vector2Int.init(std.math.maxInt(i32), 0);
pub const unit_y_frac = Vector2Int.init(0, std.math.maxInt(i32));
pub const unit_nx_frac = Vector2Int.init(-std.math.maxInt(i32), 0);
pub const unit_ny_frac = Vector2Int.init(0, -std.math.maxInt(i32));
// --- INIT ---
pub inline fn initScalar(scalar: i32) Vector2Int {
return .{ .vector = @splat(scalar) };
}
pub inline fn init(x: i32, y: i32) Vector2Int {
return .{ .vector = .{ x, y } };
}
pub inline fn initArray(array: Array) Vector2Int {
return .{ .vector = array };
}
// --- CONVERSION ---
pub inline fn asArray(self: Vector2Int) Array {
return self.vector;
}
pub inline fn asVector2(self: Vector2Int) Vector2 {
return .{ .vector = @floatFromInt(self.vector) };
}
pub inline fn asVector2Frac(self: Vector2Int) Vector2 {
const numerator: @Vector(2, f64) = @floatFromInt(self.vector);
const denominator: @Vector(2, f64) = @splat(std.math.maxInt(i32));
return .{ .vector = @floatCast(numerator / denominator) };
}
pub inline fn asVector3Int(self: Vector2Int, z: i32) Vector3Int {
const z_vector: @Vector(3, i32) = .{ undefined, undefined, z };
return .{ .vector = @shuffle(i32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
}
// --- ACCESSORS ---
pub inline fn getX(self: Vector2Int) i32 {
return self.vector[0];
}
pub inline fn getY(self: Vector2Int) i32 {
return self.vector[1];
}
pub inline fn setX(self: Vector2Int, x: i32) Vector2Int {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(i32, self.vector, x_vector, .{ ~@as(i32, 0), 1 }) };
}
pub inline fn setY(self: Vector2Int, y: i32) Vector2Int {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(i32, self.vector, y_vector, .{ 0, ~@as(i32, 1) }) };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Vector2Int, other: Vector2Int) Vector2Int {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector2Int, other: Vector2Int) Vector2Int {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector2Int, other: Vector2Int) Vector2Int {
return .{ .vector = self.vector * other.vector };
}
pub inline fn mulFrac(self: Vector2Int, other: Vector2Int) Vector2Int {
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32));
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
const self_wide: @Vector(2, i64) = self.vector;
const other_wide: @Vector(2, i64) = other.vector;
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
}
pub inline fn mulFracFrac(self: Vector2Int, other: Vector2Int) Vector2Int {
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
const self_wide: @Vector(2, i64) = self.vector;
const other_wide: @Vector(2, i64) = other.vector;
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
}
pub inline fn div(self: Vector2Int, other: Vector2Int) Vector2Int {
return .{ .vector = @divFloor(self.vector, other.vector) };
}
pub inline fn mod(self: Vector2Int, other: Vector2Int) Vector2Int {
return .{ .vector = @mod(self.vector, other.vector) };
}
pub inline fn negate(self: Vector2Int) Vector2Int {
return .{ .vector = -self.vector };
}
pub inline fn mulScalar(self: Vector2Int, scalar: i32) Vector2Int {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn mulScalarFloat(self: Vector2Int, scalar: f32) Vector2Int {
const self_float: @Vector(2, f64) = @floatFromInt(self.vector);
const scalar_vector_float: @Vector(2, f64) = @splat(scalar);
return .{ .vector = @intFromFloat(@round(self_float * scalar_vector_float)) };
}
pub inline fn mulScalarFrac(self: Vector2Int, scalar: i32) Vector2Int {
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32));
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
const self_wide: @Vector(2, i64) = self.vector;
const scalar_wide: @Vector(2, i64) = @splat(scalar);
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
}
pub inline fn mulScalarFracFrac(self: Vector2Int, scalar: i32) Vector2Int {
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
const self_wide: @Vector(2, i64) = self.vector;
const scalar_wide: @Vector(2, i64) = @splat(scalar);
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
}
pub inline fn divScalar(self: Vector2Int, scalar: i32) Vector2Int {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = @divFloor(self.vector, scalar_vector) };
}
pub inline fn divScalarFloat(self: Vector2Int, scalar: f32) Vector2Int {
const self_float: @Vector(2, f64) = @floatFromInt(self.vector);
const scalar_vector_float: @Vector(2, f64) = @splat(scalar);
return .{ .vector = @intFromFloat(@round(self_float / scalar_vector_float)) };
}
pub inline fn modScalar(self: Vector2Int, scalar: i32) Vector2Int {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = @mod(self.vector, scalar_vector) };
}
pub inline fn abs(self: Vector2Int) Vector2Int {
return .{ .vector = @intCast(@abs(self.vector)) };
}
pub inline fn sign(self: Vector2Int) Vector2Int {
return .{ .vector = std.math.sign(self.vector) };
}
// --- SWIZZLE ---
pub inline fn swizzle2(self: Vector2Int, comptime mask: [2]Mask) Vector2Int {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
}
pub inline fn swizzle3(self: Vector2Int, comptime mask: [3]Mask) Vector3Int {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
}
// --- OTHER ---
pub inline fn lenSquared(self: Vector2Int) i64 {
const self_wide: @Vector(2, i64) = self.vector;
return @reduce(.Add, self_wide * self_wide);
}
pub inline fn dot(self: Vector2Int, other: Vector2Int) i64 {
const self_wide: @Vector(2, i64) = self.vector;
const other_wide: @Vector(2, i64) = other.vector;
return @reduce(.Add, self_wide * other_wide);
}
pub inline fn cross(self: Vector2Int, other: Vector2Int) i64 {
return @as(i64, self.getX()) * @as(i64, other.getY()) - @as(i64, self.getY()) * @as(i64, other.getX());
}
};

View File

@@ -1,166 +0,0 @@
const std = @import("std");
const math = @import("../math.zig");
const Vector2 = @import("Vector2.zig").Vector2;
const f32x8 = math.f32x8;
const ps = math.ps;
pub const Vector2x8 = extern struct {
x: f32x8,
y: f32x8,
pub const zero = Vector2x8.init(ps(0), ps(0));
pub const one = Vector2x8.init(ps(1), ps(1));
pub const unit_x = Vector2x8.init(ps(1), ps(0));
pub const unit_y = Vector2x8.init(ps(0), ps(1));
pub const unit_nx = Vector2x8.init(ps(-1), ps(0));
pub const unit_ny = Vector2x8.init(ps(0), ps(-1));
// --- INIT ---
pub inline fn initScalar(x: f32, y: f32) Vector2x8 {
return .{ .x = ps(x), .y = ps(y) };
}
pub inline fn initScalars(x: f32x8, y: f32x8) Vector2x8 {
return .{ .x = x, .y = y };
}
pub inline fn initVector(vector: Vector2) Vector2x8 {
return .{ .x = ps(vector.getX()), .y = ps(vector.getY()) };
}
pub inline fn initVectors(vectors: [8]Vector2) Vector2x8 {
const v0: f32x8 = @as([8]f32, @bitCast(vectors[0..4].*));
const v1: f32x8 = @as([8]f32, @bitCast(vectors[4..8].*));
const x: f32x8 = @shuffle(f32, v0, v1, [_]i32{ 0, 2, 4, 6, ~@as(i32, 0), ~@as(i32, 2), ~@as(i32, 4), ~@as(i32, 6) });
const y: f32x8 = @shuffle(f32, v0, v1, [_]i32{ 1, 3, 5, 7, ~@as(i32, 1), ~@as(i32, 3), ~@as(i32, 5), ~@as(i32, 7) });
return .{ .x = x, .y = y };
}
// --- CONVERSION ---
pub inline fn asVectors(self: Vector2x8) [8]Vector2 {
const v0: f32x8 = @shuffle(f32, self.x, self.y, [_]i32{ 0, ~@as(i32, 0), 1, ~@as(i32, 1), 2, ~@as(i32, 2), 3, ~@as(i32, 3) });
const v1: f32x8 = @shuffle(f32, self.x, self.y, [_]i32{ 4, ~@as(i32, 4), 5, ~@as(i32, 5), 6, ~@as(i32, 6), 7, ~@as(i32, 7) });
return @as([4]Vector2, @bitCast(@as([8]f32, v0))) ++ @as([4]Vector2, @bitCast(@as([8]f32, v1)));
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Vector2x8, other: Vector2x8) Vector2x8 {
return .{
.x = self.x + other.x,
.y = self.y + other.y,
};
}
pub inline fn sub(self: Vector2x8, other: Vector2x8) Vector2x8 {
return .{
.x = self.x - other.x,
.y = self.y - other.y,
};
}
pub inline fn mul(self: Vector2x8, other: Vector2x8) Vector2x8 {
return .{
.x = self.x * other.x,
.y = self.y * other.y,
};
}
pub inline fn div(self: Vector2x8, other: Vector2x8) Vector2x8 {
return .{
.x = self.x / other.x,
.y = self.y / other.y,
};
}
pub inline fn negate(self: Vector2x8) Vector2x8 {
return .{
.x = -self.x,
.y = -self.y,
};
}
pub inline fn mulScalar(self: Vector2x8, scalar: f32) Vector2x8 {
return .{
.x = self.x * ps(scalar),
.y = self.y * ps(scalar),
};
}
pub inline fn mulScalars(self: Vector2x8, scalar: f32x8) Vector2x8 {
return .{
.x = self.x * scalar,
.y = self.y * scalar,
};
}
pub inline fn divScalar(self: Vector2x8, scalar: f32) Vector2x8 {
return .{
.x = self.x / ps(scalar),
.y = self.y / ps(scalar),
};
}
pub inline fn divScalars(self: Vector2x8, scalar: f32x8) Vector2x8 {
return .{
.x = self.x / scalar,
.y = self.y / scalar,
};
}
// --- OTHER ---
pub inline fn len(self: Vector2x8) f32x8 {
return @sqrt(self.x * self.x + self.y * self.y);
}
pub inline fn lenSquared(self: Vector2x8) f32x8 {
return self.x * self.x + self.y * self.y;
}
pub inline fn normalize(self: Vector2x8) Vector2x8 {
const len_vector: f32x8 = @sqrt(self.x * self.x + self.y * self.y);
return .{
.x = self.x / len_vector,
.y = self.y / len_vector,
};
}
pub inline fn dot(self: Vector2x8, other: Vector2x8) f32x8 {
return self.x * other.x + self.y * other.y;
}
pub inline fn cross(self: Vector2x8, other: Vector2x8) f32x8 {
return self.x * other.y - self.y * other.x;
}
pub inline fn lerp(self: Vector2x8, other: Vector2x8, t: f32x8) Vector2x8 {
const s: f32x8 = ps(1.0) - t;
return .{
.x = self.x * s + other.x * t,
.y = self.y * s + other.y * t,
};
}
pub inline fn rotate(self: Vector2x8, angle_rad: f32) Vector2x8 {
const c = @cos(angle_rad);
const s = @sin(angle_rad);
return .{
.x = self.x * ps(c) - self.y * ps(s),
.y = self.x * ps(s) + self.y * ps(c),
};
}
pub inline fn rotatev(self: Vector2x8, angle_rad: f32x8) Vector2x8 {
const c = @cos(angle_rad);
const s = @sin(angle_rad);
return .{
.x = self.x * c - self.y * s,
.y = self.x * s + self.y * c,
};
}
};

View File

@@ -1,188 +0,0 @@
const std = @import("std");
const Quaternion = @import("Quaternion.zig").Quaternion;
const Vector2 = @import("Vector2.zig").Vector2;
const Vector3Int = @import("Vector3Int.zig").Vector3Int;
const Vector4 = @import("Vector4.zig").Vector4;
pub const Vector3 = extern struct {
vector: Vector,
pub const Vector = @Vector(3, f32);
pub const Array = [3]f32;
pub const Mask = enum(i32) { x = 0, y = 1, z = 2 };
pub const zero = Vector3.initScalar(0);
pub const one = Vector3.initScalar(1);
pub const unit_x = Vector3.init(1, 0, 0);
pub const unit_y = Vector3.init(0, 1, 0);
pub const unit_z = Vector3.init(0, 0, 1);
pub const unit_nx = Vector3.init(-1, 0, 0);
pub const unit_ny = Vector3.init(0, -1, 0);
pub const unit_nz = Vector3.init(0, 0, -1);
// --- INIT ---
pub inline fn initScalar(scalar: f32) Vector3 {
return .{ .vector = @splat(scalar) };
}
pub inline fn init(x: f32, y: f32, z: f32) Vector3 {
return .{ .vector = .{ x, y, z } };
}
pub inline fn initArray(array: Array) Vector3 {
return .{ .vector = array };
}
// --- CONVERSION ---
pub inline fn asArray(self: Vector3) Array {
return self.vector;
}
pub inline fn asArrayNorm(self: Vector3, comptime T: type) [3]T {
const scale_vector: Vector = @splat(std.math.maxInt(T));
return @as(@Vector(3, T), @intFromFloat(@round(self.vector * scale_vector)));
}
pub inline fn asVector3Int(self: Vector3) Vector3Int {
return .{ .vector = @intFromFloat(@round(self.vector)) };
}
pub inline fn asVector2IntFrac(self: Vector3) Vector3Int {
const fraction: @Vector(3, f64) = @floatCast(self.vector);
const scale: @Vector(3, f64) = @splat(std.math.maxInt(i32));
return .{ .vector = @intFromFloat(@round(fraction * scale)) };
}
pub inline fn asVector2(self: Vector3) Vector2 {
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1 }) };
}
pub inline fn asVector4(self: Vector3, w: f32) Vector4 {
const w_vector: @Vector(4, f32) = .{ undefined, undefined, undefined, w };
return .{ .vector = @shuffle(f32, self.vector, w_vector, [_]i32{ 0, 1, 2, ~@as(i32, 3) }) };
}
// --- ACCESSORS ---
pub inline fn getX(self: Vector3) f32 {
return self.vector[0];
}
pub inline fn getY(self: Vector3) f32 {
return self.vector[1];
}
pub inline fn getZ(self: Vector3) f32 {
return self.vector[2];
}
pub inline fn setX(self: Vector3, x: f32) Vector3 {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(f32, self.vector, x_vector, [_]i32{ ~@as(i32, 0), 1, 2 }) };
}
pub inline fn setY(self: Vector3, y: f32) Vector3 {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(f32, self.vector, y_vector, [_]i32{ 0, ~@as(i32, 1), 2 }) };
}
pub inline fn setZ(self: Vector3, z: f32) Vector3 {
const z_vector: Vector = @splat(z);
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector * other.vector };
}
pub inline fn div(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector / other.vector };
}
pub inline fn negate(self: Vector3) Vector3 {
return .{ .vector = -self.vector };
}
pub inline fn mulScalar(self: Vector3, scalar: f32) Vector3 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn divScalar(self: Vector3, scalar: f32) Vector3 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector / scalar_vector };
}
// --- SWIZZLE ---
pub inline fn swizzle2(self: Vector3, comptime mask: [2]Mask) Vector2 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
}
pub inline fn swizzle3(self: Vector3, comptime mask: [3]Mask) Vector3 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
}
pub inline fn swizzle4(self: Vector3, comptime mask: [4]Mask) Vector4 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([4]i32, @bitCast(mask))) };
}
// --- OTHER ---
pub inline fn len(self: Vector3) f32 {
return @sqrt(@reduce(.Add, self.vector * self.vector));
}
pub inline fn lenSquared(self: Vector3) f32 {
return @reduce(.Add, self.vector * self.vector);
}
pub inline fn normalize(self: Vector3) Vector3 {
const len_vector: Vector = @splat(@sqrt(@reduce(.Add, self.vector * self.vector)));
return .{ .vector = self.vector / len_vector };
}
pub inline fn dot(self: Vector3, other: Vector3) f32 {
return @reduce(.Add, self.vector * other.vector);
}
pub inline fn cross(self: Vector3, other: Vector3) Vector3 {
return .{
.vector = .{
self.getY() * other.getZ() - self.getZ() * other.getY(),
self.getZ() * other.getX() - self.getX() * other.getZ(),
self.getX() * other.getY() - self.getY() * other.getX(),
},
};
}
pub inline fn lerp(self: Vector3, other: Vector3, t: f32) Vector3 {
const s = 1.0 - t;
const t_vector: Vector = @splat(t);
const s_vector: Vector = @splat(s);
return .{ .vector = self * s_vector + other * t_vector };
}
pub inline fn rotate(self: Vector3, quaternion: Quaternion) Vector3 {
const quaternion_scalar = quaternion.getScalar();
const quaternion_vector = quaternion.getVector();
return .add(self, .cross(
.add(quaternion_vector, quaternion_vector),
.add(.cross(quaternion_vector, self), .mulScalar(self, quaternion_scalar)),
));
}
};

View File

@@ -1,207 +0,0 @@
const std = @import("std");
const Vector2Int = @import("Vector2Int.zig").Vector2Int;
const Vector3 = @import("Vector3.zig").Vector3;
pub const Vector3Int = extern struct {
vector: Vector,
pub const Vector = @Vector(3, i32);
pub const Array = [3]i32;
pub const Mask = enum(i32) { x = 0, y = 1, z = 2 };
pub const zero = Vector3Int.initScalar(0);
pub const one = Vector3Int.initScalar(1);
pub const one_frac = Vector3Int.initScalar(std.math.maxInt(i32));
pub const unit_x = Vector3Int.init(1, 0, 0);
pub const unit_y = Vector3Int.init(0, 1, 0);
pub const unit_z = Vector3Int.init(0, 0, 1);
pub const unit_nx = Vector3Int.init(-1, 0, 0);
pub const unit_ny = Vector3Int.init(0, -1, 0);
pub const unit_nz = Vector3Int.init(0, 0, -1);
pub const unit_x_frac = Vector3Int.init(std.math.maxInt(i32), 0, 0);
pub const unit_y_frac = Vector3Int.init(0, std.math.maxInt(i32), 0);
pub const unit_z_frac = Vector3Int.init(0, 0, std.math.maxInt(i32));
pub const unit_nx_frac = Vector3Int.init(-std.math.maxInt(i32), 0, 0);
pub const unit_ny_frac = Vector3Int.init(0, -std.math.maxInt(i32), 0);
pub const unit_nz_frac = Vector3Int.init(0, 0, -std.math.maxInt(i32));
// --- INIT ---
pub inline fn initScalar(scalar: i32) Vector3Int {
return .{ .vector = @splat(scalar) };
}
pub inline fn init(x: i32, y: i32, z: i32) Vector3Int {
return .{ .vector = .{ x, y, z } };
}
pub inline fn initArray(array: Array) Vector3Int {
return .{ .vector = array };
}
// --- CONVERSION ---
pub inline fn asArray(self: Vector3Int) Array {
return self.vector;
}
pub inline fn asVector3(self: Vector3Int) Vector3 {
return .{ .vector = @floatFromInt(self.vector) };
}
pub inline fn asVector3Frac(self: Vector3Int) Vector3 {
const numerator: @Vector(3, f64) = @floatFromInt(self.vector);
const denominator: @Vector(3, f64) = @splat(std.math.maxInt(i32));
return .{ .vector = @floatCast(numerator / denominator) };
}
pub inline fn asVector2Int(self: Vector3Int) Vector2Int {
return .{ .vector = @shuffle(i32, self.vector, undefined, [_]i32{ 0, 1 }) };
}
// --- ACCESSORS ---
pub inline fn getX(self: Vector3Int) i32 {
return self.vector[0];
}
pub inline fn getY(self: Vector3Int) i32 {
return self.vector[1];
}
pub inline fn getZ(self: Vector3Int) i32 {
return self.vector[2];
}
pub inline fn setX(self: Vector3Int, x: i32) Vector3Int {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(i32, self.vector, x_vector, [_]i32{ ~@as(i32, 0), 1, 2 }) };
}
pub inline fn setY(self: Vector3Int, y: i32) Vector3Int {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(i32, self.vector, y_vector, [_]i32{ 0, ~@as(i32, 1), 2 }) };
}
pub inline fn setZ(self: Vector3Int, z: i32) Vector3Int {
const z_vector: Vector = @splat(z);
return .{ .vector = @shuffle(i32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Vector3Int, other: Vector3Int) Vector3Int {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector3Int, other: Vector3Int) Vector3Int {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector3Int, other: Vector3Int) Vector3Int {
return .{ .vector = self.vector * other.vector };
}
pub inline fn mulFrac(self: Vector3Int, other: Vector3Int) Vector3Int {
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32));
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
const self_wide: @Vector(3, i64) = self.vector;
const other_wide: @Vector(3, i64) = other.vector;
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
}
pub inline fn mulFracFrac(self: Vector3Int, other: Vector3Int) Vector3Int {
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
const self_wide: @Vector(3, i64) = self.vector;
const other_wide: @Vector(3, i64) = other.vector;
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
}
pub inline fn div(self: Vector3Int, other: Vector3Int) Vector3Int {
return .{ .vector = @divFloor(self.vector, other.vector) };
}
pub inline fn mod(self: Vector3Int, other: Vector3Int) Vector3Int {
return .{ .vector = @mod(self.vector, other.vector) };
}
pub inline fn negate(self: Vector3Int) Vector3Int {
return .{ .vector = -self.vector };
}
pub inline fn mulScalar(self: Vector3Int, scalar: i32) Vector3Int {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn mulScalarFloat(self: Vector3Int, scalar: f32) Vector3Int {
const self_float: @Vector(3, f64) = @floatFromInt(self.vector);
const scalar_vector_float: @Vector(3, f64) = @splat(scalar);
return .{ .vector = @intFromFloat(@round(self_float * scalar_vector_float)) };
}
pub inline fn mulScalarFrac(self: Vector3Int, scalar: i32) Vector3Int {
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32));
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(3, u6), @splat(1));
const self_wide: @Vector(3, i64) = self;
const scalar_wide: @Vector(3, i64) = @splat(scalar);
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
}
pub inline fn mulScalarFracFrac(self: Vector3Int, scalar: i32) Vector3Int {
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(3, u6), @splat(1));
const self_wide: @Vector(3, i64) = self;
const scalar_wide: @Vector(3, i64) = @splat(scalar);
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
}
pub inline fn divScalar(self: Vector3Int, scalar: i32) Vector3Int {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = @divFloor(self.vector, scalar_vector) };
}
pub inline fn divScalarFloat(self: Vector3Int, scalar: f32) Vector3Int {
const self_float: @Vector(3, f64) = @floatFromInt(self.vector);
const scalar_vector_float: @Vector(3, f64) = @splat(scalar);
return .{ .vector = @intFromFloat(@round(self_float / scalar_vector_float)) };
}
pub inline fn modScalar(self: Vector3Int, scalar: i32) Vector3Int {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = @mod(self.vector, scalar_vector) };
}
pub inline fn abs(self: Vector3Int) Vector3Int {
return .{ .vector = @intCast(@abs(self.vector)) };
}
pub inline fn sign(self: Vector3Int) Vector3Int {
return .{ .vector = std.math.sign(self.vector) };
}
// --- SWIZZLE ---
pub inline fn swizzle2(self: Vector3Int, comptime mask: [2]Mask) Vector2Int {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
}
pub inline fn swizzle3(self: Vector3Int, comptime mask: [3]Mask) Vector3Int {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
}
// --- OTHER ---
pub inline fn lenSquared(self: Vector3Int) i64 {
const self_wide: @Vector(2, i64) = self.vector;
return @reduce(.Add, self_wide * self_wide);
}
pub inline fn dot(self: Vector3Int, other: Vector3Int) i64 {
const self_wide: @Vector(3, i64) = self.vector;
const other_wide: @Vector(3, i64) = other.vector;
return @reduce(.Add, self_wide * other_wide);
}
};

View File

@@ -1,166 +0,0 @@
const std = @import("std");
const Vector2 = @import("Vector2.zig").Vector2;
const Vector3 = @import("Vector3.zig").Vector3;
pub const Vector4 = extern struct {
vector: Vector,
pub const Vector = @Vector(4, f32);
pub const Array = [4]f32;
pub const Mask = enum(i32) { x = 0, y = 1, z = 2, w = 3 };
pub const zero = Vector4.initScalar(0);
pub const one = Vector4.initScalar(1);
pub const unit_x = Vector4.init(1, 0, 0, 0);
pub const unit_y = Vector4.init(0, 1, 0, 0);
pub const unit_z = Vector4.init(0, 0, 1, 0);
pub const unit_w = Vector4.init(0, 0, 0, 1);
pub const unit_nx = Vector4.init(-1, 0, 0, 0);
pub const unit_ny = Vector4.init(0, -1, 0, 0);
pub const unit_nz = Vector4.init(0, 0, -1, 0);
pub const unit_nw = Vector4.init(0, 0, 0, -1);
// --- INIT ---
pub inline fn initScalar(scalar: f32) Vector4 {
return .{ .vector = @splat(scalar) };
}
pub inline fn init(x: f32, y: f32, z: f32, w: f32) Vector4 {
return .{ .vector = .{ x, y, z, w } };
}
pub inline fn initArray(array: Array) Vector4 {
return .{ .vector = array };
}
// --- CONVERSION ---
pub inline fn asArray(self: Vector4) Array {
return self.vector;
}
pub inline fn asArrayNorm(self: Vector4, comptime T: type) [4]T {
const scale_vector: Vector = @splat(std.math.maxInt(T));
return @as(@Vector(4, T), @intFromFloat(@round(self.vector * scale_vector)));
}
pub inline fn asVector2(self: Vector4) Vector2 {
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1 }) };
}
pub inline fn asVector3(self: Vector4) Vector3 {
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1, 2 }) };
}
// --- ACCESSORS ---
pub inline fn getX(self: Vector4) f32 {
return self.vector[0];
}
pub inline fn getY(self: Vector4) f32 {
return self.vector[1];
}
pub inline fn getZ(self: Vector4) f32 {
return self.vector[2];
}
pub inline fn getW(self: Vector4) f32 {
return self.vector[3];
}
pub inline fn setX(self: Vector4, x: f32) Vector4 {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(f32, self.vector, x_vector, [_]i32{ ~@as(i32, 0), 1, 2, 3 }) };
}
pub inline fn setY(self: Vector4, y: f32) Vector4 {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(f32, self.vector, y_vector, [_]i32{ 0, ~@as(i32, 1), 2, 3 }) };
}
pub inline fn setZ(self: Vector4, z: f32) Vector4 {
const z_vector: Vector = @splat(z);
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2), 3 }) };
}
pub inline fn setW(self: Vector4, w: f32) Vector4 {
const w_vector: Vector = @splat(w);
return .{ .vector = @shuffle(f32, self.vector, w_vector, [_]i32{ 0, 1, 2, ~@as(i32, 3) }) };
}
// --- COMPONENT-WISE ---
pub inline fn add(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector * other.vector };
}
pub inline fn div(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector / other.vector };
}
pub inline fn negate(self: Vector4) Vector4 {
return .{ .vector = -self.vector };
}
pub inline fn mulScalar(self: Vector4, scalar: f32) Vector4 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn divScalar(self: Vector4, scalar: f32) Vector4 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector / scalar_vector };
}
// --- SWIZZLE ---
pub inline fn swizzle2(self: Vector4, comptime mask: [2]Mask) Vector2 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
}
pub inline fn swizzle3(self: Vector4, comptime mask: [3]Mask) Vector3 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
}
pub inline fn swizzle4(self: Vector4, comptime mask: [4]Mask) Vector4 {
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([4]i32, @bitCast(mask))) };
}
// --- OTHER ---
pub inline fn len(self: Vector4) f32 {
return @sqrt(@reduce(.Add, self.vector * self.vector));
}
pub inline fn lenSquared(self: Vector4) f32 {
return @reduce(.Add, self.vector * self.vector);
}
pub inline fn normalize(self: Vector4) Vector4 {
const len_vector: Vector = @splat(@sqrt(@reduce(.Add, self.vector * self.vector)));
return .{ .vector = self.vector / len_vector };
}
pub inline fn dot(self: Vector4, other: Vector4) f32 {
return @reduce(.Add, self.vector * other.vector);
}
pub inline fn lerp(self: Vector4, other: Vector4, t: f32) Vector4 {
const s = 1.0 - t;
const t_vector: Vector = @splat(t);
const s_vector: Vector = @splat(s);
return .{ .vector = self * s_vector + other * t_vector };
}
};

View File

@@ -1,26 +1,13 @@
const std = @import("std"); const std = @import("std");
const math = @import("../math.zig"); const vm = @import("vecmath");
const Vector2 = math.Vector2;
const Vector2x8 = math.Vector2x8;
const f32x8 = math.f32x8;
const i32x8 = math.i32x8;
const u32x8 = math.u32x8;
const u64x8 = math.u64x8;
const ps = math.ps;
const epi32 = math.epi32;
const epu32 = math.epu32;
const epu64x2 = math.epu64x2;
const prime_x: u64 = 17061574742423305691; const prime_x: u64 = 17061574742423305691;
const prime_y: u64 = 10555943830568207707; const prime_y: u64 = 10555943830568207707;
const prime_perm: u64 = 15540206209889782181; const prime_perm: u64 = 15540206209889782181;
const prime_xv: u64x8 = epu64x2(prime_x); const prime_xv: @Vector(8, u64) = @splat(prime_x);
const prime_yv: u64x8 = epu64x2(prime_y); const prime_yv: @Vector(8, u64) = @splat(prime_y);
const prime_permv: u64x8 = epu64x2(prime_perm); const prime_permv: @Vector(8, u64) = @splat(prime_perm);
fn perm(seed: u64, x: i32, y: i32) i32 { fn perm(seed: u64, x: i32, y: i32) i32 {
var hash: u64 = seed; var hash: u64 = seed;
@@ -31,13 +18,13 @@ fn perm(seed: u64, x: i32, y: i32) i32 {
return @bitCast(@as(u32, @truncate(hash))); return @bitCast(@as(u32, @truncate(hash)));
} }
fn permv(seed: u64, x: i32x8, y: i32x8) i32x8 { fn permv(seed: u64, x: vm.i32x8, y: vm.i32x8) vm.i32x8 {
var hash: u64x8 = epu64x2(seed); var hash: @Vector(8, u64) = @splat(seed);
hash ^= prime_xv *% @as(u32x8, @bitCast(x)); hash ^= prime_xv *% @as(vm.u32x8, @bitCast(x));
hash ^= prime_yv *% @as(u32x8, @bitCast(y)); hash ^= prime_yv *% @as(vm.u32x8, @bitCast(y));
hash = hash *% hash *% hash *% prime_permv; hash = hash *% hash *% hash *% prime_permv;
hash = (hash >> @splat(26)) ^ hash; hash = (hash >> @splat(26)) ^ hash;
return @bitCast(@as(u32x8, @truncate(hash))); return @bitCast(@as(vm.u32x8, @truncate(hash)));
} }
fn grad2(hash: i32, x: f32, y: f32) f32 { fn grad2(hash: i32, x: f32, y: f32) f32 {
@@ -47,26 +34,26 @@ fn grad2(hash: i32, x: f32, y: f32) f32 {
return (if (h & 0b001 != 0) -u else u) + (if (h & 0b010 != 0) -2 * v else 2 * v); return (if (h & 0b001 != 0) -u else u) + (if (h & 0b010 != 0) -2 * v else 2 * v);
} }
fn grad2x8(hash: i32x8, x: f32x8, y: f32x8) f32x8 { fn grad2x8(hash: vm.i32x8, x: vm.f32x8, y: vm.f32x8) vm.f32x8 {
const h: i32x8 = hash & epi32(0b111); const h: vm.i32x8 = hash & vm.epi32(0b111);
const u: f32x8 = @select(f32, h < epi32(4), x, y); const u: vm.f32x8 = @select(f32, h < vm.epi32(4), x, y);
const v: f32x8 = @select(f32, h < epi32(4), y, x); const v: vm.f32x8 = @select(f32, h < vm.epi32(4), y, x);
const r1: f32x8 = @select(f32, h & epi32(0b001) != epi32(0), -u, u); const r1: vm.f32x8 = @select(f32, h & vm.epi32(0b001) != vm.epi32(0), -u, u);
const r2: f32x8 = @select(f32, h & epi32(0b010) != epi32(0), ps(-2) * v, ps(2) * v); const r2: vm.f32x8 = @select(f32, h & vm.epi32(0b010) != vm.epi32(0), vm.ps(-2) * v, vm.ps(2) * v);
return r1 + r2; return r1 + r2;
} }
const F2: f32 = (@sqrt(@as(f32, 3)) - 1) / 2; const F2: f32 = (@sqrt(@as(f32, 3)) - 1) / 2;
const G2: f32 = (3 - @sqrt(@as(f32, 3))) / 6; const G2: f32 = (3 - @sqrt(@as(f32, 3))) / 6;
const F2v: f32x8 = ps(F2); const F2v: vm.f32x8 = vm.ps(F2);
const G2v: f32x8 = ps(G2); const G2v: vm.f32x8 = vm.ps(G2);
// NOTE No idea why this value, derived experimentally // NOTE No idea why this value, derived experimentally
const noise2_scale: f32 = 34.11; const noise2_scale: f32 = 34.11;
const noise2x8_scale: f32x8 = ps(noise2_scale); const noise2x8_scale: vm.f32x8 = vm.ps(noise2_scale);
pub fn noise2(seed: u64, v: Vector2) f32 { pub fn noise2(seed: u64, v: vm.Vector2) f32 {
const x: f32, const y: f32 = v.asArray(); const x: f32, const y: f32 = v.asArray();
const s: f32 = (x + y) * F2; const s: f32 = (x + y) * F2;
@@ -106,43 +93,43 @@ pub fn noise2(seed: u64, v: Vector2) f32 {
return ret; return ret;
} }
pub fn noise2x8(seed: u64, v: Vector2x8) f32x8 { pub fn noise2x8(seed: u64, v: vm.Vector2x8) vm.f32x8 {
const x: f32x8 = v.x; const x: vm.f32x8 = v.x;
const y: f32x8 = v.y; const y: vm.f32x8 = v.y;
const s: f32x8 = (x + y) * F2v; const s: vm.f32x8 = (x + y) * F2v;
const xs: f32x8 = x + s; const xs: vm.f32x8 = x + s;
const ys: f32x8 = y + s; const ys: vm.f32x8 = y + s;
const i: i32x8 = @intFromFloat(@floor(xs)); const i: vm.i32x8 = @intFromFloat(@floor(xs));
const j: i32x8 = @intFromFloat(@floor(ys)); const j: vm.i32x8 = @intFromFloat(@floor(ys));
const t: f32x8 = @as(f32x8, @floatFromInt(i + j)) * G2v; const t: vm.f32x8 = @as(vm.f32x8, @floatFromInt(i + j)) * G2v;
const X0: f32x8 = @as(f32x8, @floatFromInt(i)) - t; const X0: vm.f32x8 = @as(vm.f32x8, @floatFromInt(i)) - t;
const Y0: f32x8 = @as(f32x8, @floatFromInt(j)) - t; const Y0: vm.f32x8 = @as(vm.f32x8, @floatFromInt(j)) - t;
const x0: f32x8 = x - X0; const x0: vm.f32x8 = x - X0;
const y0: f32x8 = y - Y0; const y0: vm.f32x8 = y - Y0;
const _i1: i32x8 = @select(i32, x0 > y0, epi32(1), epi32(0)); const _i1: vm.i32x8 = @select(i32, x0 > y0, vm.epi32(1), vm.epi32(0));
const _j1: i32x8 = @select(i32, x0 > y0, epi32(0), epi32(1)); const _j1: vm.i32x8 = @select(i32, x0 > y0, vm.epi32(0), vm.epi32(1));
const x1: f32x8 = x0 - @as(f32x8, @floatFromInt(_i1)) + G2v; const x1: vm.f32x8 = x0 - @as(vm.f32x8, @floatFromInt(_i1)) + G2v;
const y1: f32x8 = y0 - @as(f32x8, @floatFromInt(_j1)) + G2v; const y1: vm.f32x8 = y0 - @as(vm.f32x8, @floatFromInt(_j1)) + G2v;
const x2: f32x8 = x0 - ps(1) + ps(2) * G2v; const x2: vm.f32x8 = x0 - vm.ps(1) + vm.ps(2) * G2v;
const y2: f32x8 = y0 - ps(1) + ps(2) * G2v; const y2: vm.f32x8 = y0 - vm.ps(1) + vm.ps(2) * G2v;
const t0: f32x8 = ps(0.5) - x0 * x0 - y0 * y0; const t0: vm.f32x8 = vm.ps(0.5) - x0 * x0 - y0 * y0;
const t1: f32x8 = ps(0.5) - x1 * x1 - y1 * y1; const t1: vm.f32x8 = vm.ps(0.5) - x1 * x1 - y1 * y1;
const t2: f32x8 = ps(0.5) - x2 * x2 - y2 * y2; const t2: vm.f32x8 = vm.ps(0.5) - x2 * x2 - y2 * y2;
const gi0: i32x8 = permv(seed, i, j); const gi0: vm.i32x8 = permv(seed, i, j);
const gi1: i32x8 = permv(seed, i + _i1, j + _j1); const gi1: vm.i32x8 = permv(seed, i + _i1, j + _j1);
const gi2: i32x8 = permv(seed, i + epi32(1), j + epi32(1)); const gi2: vm.i32x8 = permv(seed, i + vm.epi32(1), j + vm.epi32(1));
const n0: f32x8 = @select(f32, t0 < ps(0), ps(0), (t0 * t0) * (t0 * t0) * grad2x8(gi0, x0, y0)); const n0: vm.f32x8 = @select(f32, t0 < vm.ps(0), vm.ps(0), (t0 * t0) * (t0 * t0) * grad2x8(gi0, x0, y0));
const n1: f32x8 = @select(f32, t1 < ps(0), ps(0), (t1 * t1) * (t1 * t1) * grad2x8(gi1, x1, y1)); const n1: vm.f32x8 = @select(f32, t1 < vm.ps(0), vm.ps(0), (t1 * t1) * (t1 * t1) * grad2x8(gi1, x1, y1));
const n2: f32x8 = @select(f32, t2 < ps(0), ps(0), (t2 * t2) * (t2 * t2) * grad2x8(gi2, x2, y2)); const n2: vm.f32x8 = @select(f32, t2 < vm.ps(0), vm.ps(0), (t2 * t2) * (t2 * t2) * grad2x8(gi2, x2, y2));
const ret: f32x8 = noise2x8_scale * (n0 + n1 + n2); const ret: vm.f32x8 = noise2x8_scale * (n0 + n1 + n2);
std.debug.assert(@reduce(.And, ret >= ps(-1)) and @reduce(.And, ret <= ps(1))); std.debug.assert(@reduce(.And, (ret >= vm.ps(-1)) & (ret <= vm.ps(1))));
return ret; return ret;
} }

View File

@@ -1,12 +1,9 @@
const math = @import("math.zig"); const std = @import("std");
const vm = @import("vecmath");
const Materials = @import("assets/Materials.zig"); const Materials = @import("assets/Materials.zig");
const Matrix4x4 = math.Matrix4x4;
const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer; const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer;
const Textures = @import("assets/Textures.zig"); const Textures = @import("assets/Textures.zig");
const Vector2 = math.Vector2;
const Vector3 = math.Vector3;
const Vector4 = math.Vector4;
pub const VertexBuffer = GenericBuffer(void, Vertex); pub const VertexBuffer = GenericBuffer(void, Vertex);
pub const IndexBuffer = GenericBuffer(void, Index); pub const IndexBuffer = GenericBuffer(void, Index);
@@ -17,17 +14,29 @@ pub const MaterialBuffer = GenericBuffer(void, Material);
pub const ObjectUniformsBuffer = GenericBuffer(void, ObjectUniforms); pub const ObjectUniformsBuffer = GenericBuffer(void, ObjectUniforms);
pub const Vertex = extern struct { pub const Vertex = extern struct {
positionOS: [3]f32, positionOS: vm.Vector3,
texCoord: [2]u16, texCoord: [2]u16,
normalOS: [3]i8, normalOS: [3]i8,
tangentOS: [4]i8, tangentOS: [4]i8,
pub fn init(position_os: Vector3, tex_coord: Vector2, normal_os: Vector3, tangent_os: Vector4) Vertex { pub fn init(position_os: vm.Vector3, tex_coord: vm.Vector2, normal_os: vm.Vector3, tangent_os: vm.Vector4) Vertex {
return .{ return .{
.positionOS = position_os.asArray(), .positionOS = position_os,
.texCoord = tex_coord.asArrayNorm(u16), .texCoord = [_]u16{
.normalOS = normal_os.asArrayNorm(i8), @intFromFloat(@round(tex_coord.x * std.math.maxInt(u16))),
.tangentOS = tangent_os.asArrayNorm(i8), @intFromFloat(@round(tex_coord.y * std.math.maxInt(u16))),
},
.normalOS = [_]i8{
@intFromFloat(@round(normal_os.x * std.math.maxInt(i8))),
@intFromFloat(@round(normal_os.y * std.math.maxInt(i8))),
@intFromFloat(@round(normal_os.z * std.math.maxInt(i8))),
},
.tangentOS = [_]i8{
@intFromFloat(@round(tangent_os.x * std.math.maxInt(i8))),
@intFromFloat(@round(tangent_os.y * std.math.maxInt(i8))),
@intFromFloat(@round(tangent_os.z * std.math.maxInt(i8))),
@intFromFloat(@round(tangent_os.w * std.math.maxInt(i8))),
},
}; };
} }
}; };
@@ -35,46 +44,38 @@ pub const Vertex = extern struct {
pub const Index = u16; pub const Index = u16;
pub const GlobalUniforms = extern struct { pub const GlobalUniforms = extern struct {
matrixWStoVS: [16]f32, matrixWStoVS: vm.Matrix4x4,
matrixVStoCS: [16]f32, matrixVStoCS: vm.Matrix4x4,
ambientLight: [3]f32, ambientLight: vm.Vector3,
pub fn init(matrix_ws_to_vs: Matrix4x4, matrix_vs_to_cs: Matrix4x4, ambient_light: Vector3) GlobalUniforms {
return .{
.matrixWStoVS = matrix_ws_to_vs.asArray(),
.matrixVStoCS = matrix_vs_to_cs.asArray(),
.ambientLight = ambient_light.asArray(),
};
}
}; };
pub const PointLight = extern struct { pub const PointLight = extern struct {
positionWS: [3]f32, positionWS: vm.Vector3,
color: [3]f32, color: vm.Vector3,
pub fn init(position_ws: Vector3, color: Vector3) PointLight { pub fn init(position_ws: vm.Vector3, color: vm.Vector3) PointLight {
return .{ return .{
.positionWS = position_ws.asArray(), .positionWS = position_ws,
.color = color.asArray(), .color = color,
}; };
} }
}; };
pub const DirectionalLight = extern struct { pub const DirectionalLight = extern struct {
directionWS: [3]f32, directionWS: vm.Vector3,
color: [3]f32, color: vm.Vector3,
pub fn init(direction_ws: Vector3, color: Vector3) DirectionalLight { pub fn init(direction_ws: vm.Vector3, color: vm.Vector3) DirectionalLight {
return .{ return .{
.directionWS = direction_ws.asArray(), .directionWS = direction_ws,
.color = color.asArray(), .color = color,
}; };
} }
}; };
pub const Material = extern struct { pub const Material = extern struct {
base_color: [3]f32, base_color: vm.Vector3,
emissive: [3]f32, emissive: vm.Vector3,
ior: f32, ior: f32,
metallic: f32, metallic: f32,
normal_scale: f32, normal_scale: f32,
@@ -88,18 +89,10 @@ pub const Material = extern struct {
}; };
pub const ObjectUniforms = extern struct { pub const ObjectUniforms = extern struct {
matrixOStoWS: [16]f32, matrixOStoWS: vm.Matrix4x4,
matrixOStoWSNormal: [16]f32, matrixOStoWSNormal: vm.Matrix4x4,
material: Materials.Id, material: Materials.Id,
pub fn init(matrix_os_to_ws: Matrix4x4, matrix_ow_to_ws_normal: Matrix4x4, material: Materials.Id) ObjectUniforms {
return .{
.matrixOStoWS = matrix_os_to_ws.asArray(),
.matrixOStoWSNormal = matrix_ow_to_ws_normal.asArray(),
.material = material,
};
}
}; };
pub const equirect_to_cube_comp_spv align(4) = @embedFile("shaders/equirect_to_cube_comp.spv").*; pub const equirect_to_cube_comp_spv align(4) = @embedFile("shaders/equirect_to_cube_comp.spv").*;

View File

@@ -1,25 +1,19 @@
const std = @import("std"); const std = @import("std");
const math = @import("math.zig"); const math = @import("math.zig");
const vm = @import("vecmath");
const Vector2 = math.Vector2;
const Vector2x8 = math.Vector2x8;
const f32x8 = math.f32x8;
const i32x8 = math.i32x8;
const ps = math.ps;
const Noise = struct { const Noise = struct {
horizontal_scale: f32, horizontal_scale: f32,
value_median: f32, value_median: f32,
value_amplitude: f32, value_amplitude: f32,
pub fn sample(self: Noise, seed: u64, pos: Vector2) f32 { pub fn sample(self: Noise, seed: u64, pos: vm.Vector2) f32 {
return math.noise2(seed, pos.divScalar(self.horizontal_scale)) * self.value_amplitude + self.value_median; return math.noise2(seed, pos.divScalar(self.horizontal_scale)) * self.value_amplitude + self.value_median;
} }
pub fn samplev(self: Noise, seed: u64, pos: Vector2x8) f32x8 { pub fn samplev(self: Noise, seed: u64, pos: vm.Vector2x8) vm.f32x8 {
return math.noise2x8(seed, pos.divScalar(self.horizontal_scale)) * ps(self.value_amplitude) + ps(self.value_median); return math.noise2x8(seed, pos.divScalarSingle(self.horizontal_scale)) * vm.ps(self.value_amplitude) + vm.ps(self.value_median);
} }
}; };
@@ -35,22 +29,22 @@ const noise_secondary: Noise = .{
.value_amplitude = 0.5, .value_amplitude = 0.5,
}; };
pub fn heightF(seed: u64, pos: Vector2) f32 { pub fn heightF(seed: u64, pos: vm.Vector2) f32 {
const main = noise_main.sample(seed, pos); const main = noise_main.sample(seed, pos);
const secondary = noise_secondary.sample(seed, pos); const secondary = noise_secondary.sample(seed, pos);
return @round(main + secondary); return @round(main + secondary);
} }
pub fn heightFv(seed: u64, pos: Vector2x8) f32x8 { pub fn heightFv(seed: u64, pos: vm.Vector2x8) vm.f32x8 {
const main = noise_main.samplev(seed, pos); const main = noise_main.samplev(seed, pos);
const secondary = noise_secondary.samplev(seed, pos); const secondary = noise_secondary.samplev(seed, pos);
return @round(main + secondary); return @round(main + secondary);
} }
pub fn heightI(seed: u64, pos: Vector2) i32 { pub fn heightI(seed: u64, pos: vm.Vector2) i32 {
return @intFromFloat(heightF(seed, pos)); return @intFromFloat(heightF(seed, pos));
} }
pub fn heightIv(seed: u64, pos: Vector2x8) i32x8 { pub fn heightIv(seed: u64, pos: vm.Vector2x8) vm.i32x8 {
return @intFromFloat(heightFv(seed, pos)); return @intFromFloat(heightFv(seed, pos));
} }