BLOK DISTROJ

This commit is contained in:
2026-01-07 14:19:49 +01:00
parent 0d171fb892
commit d96946d1a0
4 changed files with 414 additions and 134 deletions

2
castle

Submodule castle updated: 6c9a786926...31651dc96a

View File

@@ -13,11 +13,15 @@ const Iterator2 = math.Iterator2;
chunks: std.AutoHashMapUnmanaged([3]i16, Chunk),
const RaycastHit = struct {
pub const SweepHit = struct {
normal_frac: vm.Vector3Int,
projected_distance_sv: i32,
};
pub const RaycastHit = struct {
voxel: vm.Vector3Int,
};
pub fn deinit(self: *Chunks, engine: *Engine, descriptor_pool: vk.DescriptorPool, allocator: std.mem.Allocator) void {
var it = self.chunks.valueIterator();
while (it.next()) |chunk| {
@@ -48,13 +52,116 @@ pub fn getVoxelAt(self: *const Chunks, vx: vm.Vector3Int) ?Blocks.Id {
}
}
pub fn destroyVoxelAt(self: *const Chunks, vx: vm.Vector3Int, engine: *Engine, blocks: *const Blocks, allocator: std.mem.Allocator) !void {
const min_ck = vm.Vector3Int.initScalar(std.math.minInt(i16));
const max_ck = vm.Vector3Int.initScalar(std.math.maxInt(i16));
const ck = vx.divScalar(c.vx_per_ck);
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;
}
const x: i16 = @intCast(ck.x);
const y: i16 = @intCast(ck.y);
const z: i16 = @intCast(ck.z);
if (self.chunks.getPtr(.{ x, y, z })) |chunk| {
const ckvx = vx.modScalar(c.vx_per_ck);
const block = &chunk.blocks[@intCast(ckvx.z)][@intCast(ckvx.y)][@intCast(ckvx.x)];
if (block.* != .air) {
block.* = .air;
try chunk.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x + 1, y, z }),
.negative_x = self.chunks.getPtr(.{ x - 1, y, z }),
.positive_y = self.chunks.getPtr(.{ x, y + 1, z }),
.negative_y = self.chunks.getPtr(.{ x, y - 1, z }),
.positive_z = self.chunks.getPtr(.{ x, y, z + 1 }),
.negative_z = self.chunks.getPtr(.{ x, y, z - 1 }),
}, allocator);
if (ckvx.x == 0) {
if (self.chunks.getPtr(.{ x - 1, y, z })) |neighbor| {
try neighbor.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x, y, z }),
.negative_x = self.chunks.getPtr(.{ x - 2, y, z }),
.positive_y = self.chunks.getPtr(.{ x - 1, y + 1, z }),
.negative_y = self.chunks.getPtr(.{ x - 1, y - 1, z }),
.positive_z = self.chunks.getPtr(.{ x - 1, y, z + 1 }),
.negative_z = self.chunks.getPtr(.{ x - 1, y, z - 1 }),
}, allocator);
}
} else if (ckvx.x == c.vx_per_ck - 1) {
if (self.chunks.getPtr(.{ x + 1, y, z })) |neighbor| {
try neighbor.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x + 2, y, z }),
.negative_x = self.chunks.getPtr(.{ x, y, z }),
.positive_y = self.chunks.getPtr(.{ x + 1, y + 1, z }),
.negative_y = self.chunks.getPtr(.{ x + 1, y - 1, z }),
.positive_z = self.chunks.getPtr(.{ x + 1, y, z + 1 }),
.negative_z = self.chunks.getPtr(.{ x + 1, y, z - 1 }),
}, allocator);
}
}
if (ckvx.y == 0) {
if (self.chunks.getPtr(.{ x, y - 1, z })) |neighbor| {
try neighbor.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x + 1, y - 1, z }),
.negative_x = self.chunks.getPtr(.{ x - 1, y - 1, z }),
.positive_y = self.chunks.getPtr(.{ x, y, z }),
.negative_y = self.chunks.getPtr(.{ x, y - 2, z }),
.positive_z = self.chunks.getPtr(.{ x, y - 1, z + 1 }),
.negative_z = self.chunks.getPtr(.{ x, y - 1, z - 1 }),
}, allocator);
}
} else if (ckvx.y == c.vx_per_ck - 1) {
if (self.chunks.getPtr(.{ x, y + 1, z })) |neighbor| {
try neighbor.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x + 1, y + 1, z }),
.negative_x = self.chunks.getPtr(.{ x - 1, y + 1, z }),
.positive_y = self.chunks.getPtr(.{ x, y + 2, z }),
.negative_y = self.chunks.getPtr(.{ x, y, z }),
.positive_z = self.chunks.getPtr(.{ x, y + 1, z + 1 }),
.negative_z = self.chunks.getPtr(.{ x, y + 1, z - 1 }),
}, allocator);
}
}
if (ckvx.z == 0) {
if (self.chunks.getPtr(.{ x, y, z - 1 })) |neighbor| {
try neighbor.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x + 1, y, z - 1 }),
.negative_x = self.chunks.getPtr(.{ x - 1, y, z - 1 }),
.positive_y = self.chunks.getPtr(.{ x, y + 1, z - 1 }),
.negative_y = self.chunks.getPtr(.{ x, y - 1, z - 1 }),
.positive_z = self.chunks.getPtr(.{ x, y, z }),
.negative_z = self.chunks.getPtr(.{ x, y, z - 2 }),
}, allocator);
}
} else if (ckvx.z == c.vx_per_ck - 1) {
if (self.chunks.getPtr(.{ x, y, z + 1 })) |neighbor| {
try neighbor.refresh(engine, blocks, .{
.positive_x = self.chunks.getPtr(.{ x + 1, y, z + 1 }),
.negative_x = self.chunks.getPtr(.{ x - 1, y, z + 1 }),
.positive_y = self.chunks.getPtr(.{ x, y + 1, z + 1 }),
.negative_y = self.chunks.getPtr(.{ x, y - 1, z + 1 }),
.positive_z = self.chunks.getPtr(.{ x, y, z + 2 }),
.negative_z = self.chunks.getPtr(.{ x, y, z }),
}, allocator);
}
}
}
}
}
pub fn isSolid(self: *const Chunks, vx: vm.Vector3Int) bool {
const maybe_id = getVoxelAt(self, vx);
// NOTE `null` is considered solid, as it's out of bounds.
return maybe_id != .air;
}
pub fn sweepCastDown(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, distance_sv: i32) ?RaycastHit {
pub fn sweepCastDown(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, distance_sv: i32) ?SweepHit {
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.x);
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.y);
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.x);
@@ -84,7 +191,7 @@ pub fn sweepCastDown(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vect
return null;
}
pub fn sweepCastUp(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, distance_sv: i32) ?RaycastHit {
pub fn sweepCastUp(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, distance_sv: i32) ?SweepHit {
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.x);
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.y);
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.x);
@@ -114,11 +221,11 @@ pub fn sweepCastUp(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector
return null;
}
pub fn sweepCastHorizontal(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, ray_sv: vm.Vector2Int) ?RaycastHit {
pub fn sweepCastHorizontal(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: vm.Vector3Int, ray_sv: vm.Vector2Int) ?SweepHit {
const min_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.z);
const max_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.z);
var hit: ?RaycastHit = null;
var hit: ?SweepHit = null;
var hit_distance_squared = std.math.inf(f32);
const fdydx: f32 = @as(f32, @floatFromInt(ray_sv.y)) / @as(f32, @floatFromInt(ray_sv.x));
@@ -288,20 +395,20 @@ pub fn sweepCastHorizontal(self: *const Chunks, min_sv: vm.Vector3Int, max_sv: v
pub fn raycast(self: *const Chunks, origin_sv: vm.Vector3Int, ray_sv: vm.Vector3Int) ?RaycastHit {
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", .{
c.subvoxelsToVoxels(.border_up, origin_sv.x),
c.subvoxelsToVoxelSubvoxels(origin_sv.x),
c.subvoxelsToVoxels(.border_up, origin_sv.y),
c.subvoxelsToVoxelSubvoxels(origin_sv.y),
c.subvoxelsToVoxels(.border_up, origin_sv.z),
c.subvoxelsToVoxelSubvoxels(origin_sv.z),
c.subvoxelsToVoxels(.border_up, end_sv.x),
c.subvoxelsToVoxelSubvoxels(end_sv.x),
c.subvoxelsToVoxels(.border_up, end_sv.y),
c.subvoxelsToVoxelSubvoxels(end_sv.y),
c.subvoxelsToVoxels(.border_up, end_sv.z),
c.subvoxelsToVoxelSubvoxels(end_sv.z),
});
//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.x),
// c.subvoxelsToVoxelSubvoxels(origin_sv.x),
// c.subvoxelsToVoxels(.border_up, origin_sv.y),
// c.subvoxelsToVoxelSubvoxels(origin_sv.y),
// c.subvoxelsToVoxels(.border_up, origin_sv.z),
// c.subvoxelsToVoxelSubvoxels(origin_sv.z),
// c.subvoxelsToVoxels(.border_up, end_sv.x),
// c.subvoxelsToVoxelSubvoxels(end_sv.x),
// c.subvoxelsToVoxels(.border_up, end_sv.y),
// c.subvoxelsToVoxelSubvoxels(end_sv.y),
// c.subvoxelsToVoxels(.border_up, end_sv.z),
// c.subvoxelsToVoxelSubvoxels(end_sv.z),
//});
const ray_positive = vm.Vector3Int.init(
@intFromBool(ray_sv.x > 0),
@@ -319,37 +426,38 @@ pub fn raycast(self: *const Chunks, origin_sv: vm.Vector3Int, ray_sv: vm.Vector3
const end_vx = end_sv.sub(ray_positive).divScalar(c.sv_per_vx);
const abs_ray_sv = ray_sv.abs();
std.debug.print("Start [VX]: ({d}, {d}, {d}) | End [VX]: ({d}, {d}, {d})\n", .{
start_vx.x,
start_vx.y,
start_vx.z,
end_vx.x,
end_vx.y,
end_vx.z,
});
//std.debug.print("Start [VX]: ({d}, {d}, {d}) | End [VX]: ({d}, {d}, {d})\n", .{
// start_vx.x,
// start_vx.y,
// start_vx.z,
// end_vx.x,
// end_vx.y,
// end_vx.z,
//});
var i_index: usize = undefined;
var j_index: usize = undefined;
var k_index: usize = undefined;
const i_index: usize, const j_index: usize, const k_index: usize = blk: {
if (abs_ray_sv.x > abs_ray_sv.y and abs_ray_sv.x > abs_ray_sv.z) {
// Main axis: ±X
//std.debug.print("Order is (X, Y, Z)\n", .{});
break :blk .{ 0, 1, 2 };
} else if (abs_ray_sv.y > abs_ray_sv.z) {
// Main axis: ±Y
//std.debug.print("Order is (Y, Z, X)\n", .{});
break :blk .{ 1, 2, 0 };
} else if (abs_ray_sv.z > 0) {
// Main axis: ±Z
//std.debug.print("Order is (Z, X, Y)\n", .{});
break :blk .{ 2, 0, 1 };
} else {
std.debug.assert(abs_ray_sv.x == 0);
std.debug.assert(abs_ray_sv.y == 0);
std.debug.assert(abs_ray_sv.z == 0);
return null;
}
};
if (abs_ray_sv.x > abs_ray_sv.y and abs_ray_sv.x > abs_ray_sv.z) {
// Main axis: ±X
i_index, j_index, k_index = .{ 0, 1, 2 };
std.debug.print("Order is (X, Y, Z)\n", .{});
} else if (abs_ray_sv.y > abs_ray_sv.z) {
// Main axis: ±Y
i_index, j_index, k_index = .{ 1, 2, 0 };
std.debug.print("Order is (Y, Z, X)\n", .{});
} else if (abs_ray_sv.z > 0) {
// Main axis: ±Z
i_index, j_index, k_index = .{ 2, 0, 1 };
std.debug.print("Order is (Z, X, Y)\n", .{});
} else {
std.debug.assert(abs_ray_sv.x == 0);
std.debug.assert(abs_ray_sv.y == 0);
std.debug.assert(abs_ray_sv.z == 0);
return null;
}
var ind_buf: [3]usize = undefined;
var current_vx: [3]i32 = undefined;
const oi = origin_sv.asArray()[i_index];
const oj = origin_sv.asArray()[j_index];
@@ -359,42 +467,70 @@ pub fn raycast(self: *const Chunks, origin_sv: vm.Vector3Int, ray_sv: vm.Vector3
const dj = ray_sv.asArray()[j_index];
const dk = ray_sv.asArray()[k_index];
const rpi = ray_positive.asArray()[i_index];
const rpj = ray_positive.asArray()[j_index];
const rpk = ray_positive.asArray()[k_index];
const rni = ray_negative.asArray()[i_index];
const rnj = ray_negative.asArray()[j_index];
const rnk = ray_negative.asArray()[k_index];
var i_vx = start_vx.asArray()[i_index];
var enter_i_sv = oi;
var enter_di_sv = enter_i_sv - oi;
var enter_jdi_sv = oj * di + enter_di_sv * dj;
var enter_kdi_sv = ok * di + enter_di_sv * dk;
var enter_jdi_sv = @as(i64, oj) * @as(i64, di) + @as(i64, enter_di_sv) * @as(i64, dj);
var enter_kdi_sv = @as(i64, ok) * @as(i64, di) + @as(i64, enter_di_sv) * @as(i64, dk);
var enter_i_vx = @divFloor(enter_i_sv - ray_positive.asArray()[i_index], c.sv_per_vx);
var enter_j_vx = @divFloor(enter_jdi_sv - ray_positive.asArray()[j_index], c.sv_per_vx * di);
var enter_k_vx = @divFloor(enter_kdi_sv - ray_positive.asArray()[k_index], c.sv_per_vx * di);
var enter_i_vx: i32 = @divFloor(enter_i_sv - rpi, c.sv_per_vx);
var enter_j_vx: i32 = @intCast(@divFloor(enter_jdi_sv - rpj, c.sv_per_vx * @as(i64, di)));
var enter_k_vx: i32 = @intCast(@divFloor(enter_kdi_sv - rpk, c.sv_per_vx * @as(i64, di)));
var exit_i_sv = c.voxelsToSubvoxels(i_vx + ray_negative.asArray()[i_index]);
current_vx[i_index] = enter_i_vx;
current_vx[j_index] = enter_j_vx;
current_vx[k_index] = enter_k_vx;
var exit_i_sv = c.voxelsToSubvoxels(i_vx + rni);
var exit_di_sv = exit_i_sv - oi;
var exit_jdi_sv = oj * di + exit_di_sv * dj;
var exit_kdi_sv = ok * di + exit_di_sv * dk;
var exit_jdi_sv = @as(i64, oj) * @as(i64, di) + @as(i64, exit_di_sv) * @as(i64, dj);
var exit_kdi_sv = @as(i64, ok) * @as(i64, di) + @as(i64, exit_di_sv) * @as(i64, dk);
var exit_i_vx = @divFloor(exit_i_sv - ray_positive.asArray()[i_index], c.sv_per_vx);
var exit_j_vx = @divFloor(exit_jdi_sv - ray_positive.asArray()[j_index], c.sv_per_vx * di);
var exit_k_vx = @divFloor(exit_kdi_sv - ray_positive.asArray()[k_index], c.sv_per_vx * di);
var exit_i_vx: i32 = @divFloor(exit_i_sv - rpi, c.sv_per_vx);
var exit_j_vx: i32 = @intCast(@divFloor(exit_jdi_sv - rpj, c.sv_per_vx * @as(i64, di)));
var exit_k_vx: i32 = @intCast(@divFloor(exit_kdi_sv - rpk, c.sv_per_vx * @as(i64, di)));
std.debug.print("({d}:{X}, {d:.3}, {d:.3}) → ({d}:{X}, {d:.3}, {d:.3}) | ({d}, {d}, {d}) → ({d}, {d}, {d})\n", .{
c.subvoxelsToVoxels(.border_up, enter_i_sv),
c.subvoxelsToVoxelSubvoxels(enter_i_sv),
@as(f64, @floatFromInt(enter_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
@as(f64, @floatFromInt(enter_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
c.subvoxelsToVoxels(.border_up, exit_i_sv),
c.subvoxelsToVoxelSubvoxels(exit_i_sv),
@as(f64, @floatFromInt(exit_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
@as(f64, @floatFromInt(exit_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
enter_i_vx,
enter_j_vx,
enter_k_vx,
exit_i_vx,
exit_j_vx,
exit_k_vx,
});
var cross_i = vm.unlerpInt(enter_i_sv, exit_i_sv, c.voxelsToSubvoxels(exit_i_vx + rni));
var cross_j = vm.unlerpInt64(enter_jdi_sv, exit_jdi_sv, c.voxelsToSubvoxels(exit_j_vx + rnj) * @as(i64, di));
var cross_k = vm.unlerpInt64(enter_kdi_sv, exit_kdi_sv, c.voxelsToSubvoxels(exit_k_vx + rnk) * @as(i64, di));
//std.debug.print("({d}:{X:0>3}, {d:.3}, {d:.3}) → ({d}:{X:0>3}, {d:.3}, {d:.3}) | ({d}, {d}, {d}) → ({d}, {d}, {d}) | × ({d:.3}, {d:.3}, {d:.3})\n", .{
// c.subvoxelsToVoxels(.border_up, enter_i_sv),
// c.subvoxelsToVoxelSubvoxels(enter_i_sv),
// @as(f64, @floatFromInt(enter_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// @as(f64, @floatFromInt(enter_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// c.subvoxelsToVoxels(.border_up, exit_i_sv),
// c.subvoxelsToVoxelSubvoxels(exit_i_sv),
// @as(f64, @floatFromInt(exit_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// @as(f64, @floatFromInt(exit_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// enter_i_vx,
// enter_j_vx,
// enter_k_vx,
// exit_i_vx,
// exit_j_vx,
// exit_k_vx,
// cross_i,
// cross_j,
// cross_k,
//});
var cross_indices = order3(i_index, j_index, k_index, cross_i, cross_j, cross_k, &ind_buf);
for (cross_indices) |cross_index| {
current_vx[cross_index] += ray_sign.asArray()[cross_index];
const voxel = vm.Vector3Int.initArray(current_vx);
if (self.isSolid(voxel)) {
return .{ .voxel = voxel };
}
}
while (i_vx != end_vx.asArray()[i_index]) : (i_vx += ray_sign.asArray()[i_index]) {
enter_i_sv = exit_i_sv;
@@ -406,31 +542,47 @@ pub fn raycast(self: *const Chunks, origin_sv: vm.Vector3Int, ray_sv: vm.Vector3
enter_j_vx = exit_j_vx;
enter_k_vx = exit_k_vx;
exit_i_sv = c.voxelsToSubvoxels(i_vx + ray_positive.asArray()[i_index]);
exit_i_sv = c.voxelsToSubvoxels(i_vx + rpi);
exit_di_sv = exit_i_sv - oi;
exit_jdi_sv = oj * di + exit_di_sv * dj;
exit_kdi_sv = ok * di + exit_di_sv * dk;
exit_jdi_sv = @as(i64, oj) * @as(i64, di) + @as(i64, exit_di_sv) * @as(i64, dj);
exit_kdi_sv = @as(i64, ok) * @as(i64, di) + @as(i64, exit_di_sv) * @as(i64, dk);
exit_i_vx = @divFloor(exit_i_sv - ray_positive.asArray()[i_index], c.sv_per_vx);
exit_j_vx = @divFloor(exit_jdi_sv - ray_positive.asArray()[j_index], c.sv_per_vx * di);
exit_k_vx = @divFloor(exit_kdi_sv - ray_positive.asArray()[k_index], c.sv_per_vx * di);
exit_i_vx = @divFloor(exit_i_sv - rpi, c.sv_per_vx);
exit_j_vx = @intCast(@divFloor(exit_jdi_sv - rpj, c.sv_per_vx * @as(i64, di)));
exit_k_vx = @intCast(@divFloor(exit_kdi_sv - rpk, c.sv_per_vx * @as(i64, di)));
std.debug.print("({d}:{X}, {d:.3}, {d:.3}) → ({d}:{X}, {d:.3}, {d:.3}) | ({d}, {d}, {d}) → ({d}, {d}, {d})\n", .{
c.subvoxelsToVoxels(.border_up, enter_i_sv),
c.subvoxelsToVoxelSubvoxels(enter_i_sv),
@as(f64, @floatFromInt(enter_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
@as(f64, @floatFromInt(enter_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
c.subvoxelsToVoxels(.border_up, exit_i_sv),
c.subvoxelsToVoxelSubvoxels(exit_i_sv),
@as(f64, @floatFromInt(exit_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
@as(f64, @floatFromInt(exit_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
enter_i_vx,
enter_j_vx,
enter_k_vx,
exit_i_vx,
exit_j_vx,
exit_k_vx,
});
cross_i = vm.unlerpInt(enter_i_sv, exit_i_sv, c.voxelsToSubvoxels(exit_i_vx + rni));
cross_j = vm.unlerpInt64(enter_jdi_sv, exit_jdi_sv, c.voxelsToSubvoxels(exit_j_vx + rnj) * @as(i64, di));
cross_k = vm.unlerpInt64(enter_kdi_sv, exit_kdi_sv, c.voxelsToSubvoxels(exit_k_vx + rnk) * @as(i64, di));
//std.debug.print("({d}:{X:0>3}, {d:.3}, {d:.3}) → ({d}:{X:0>3}, {d:.3}, {d:.3}) | ({d}, {d}, {d}) → ({d}, {d}, {d}) | × ({d:.3}, {d:.3}, {d:.3})\n", .{
// c.subvoxelsToVoxels(.border_up, enter_i_sv),
// c.subvoxelsToVoxelSubvoxels(enter_i_sv),
// @as(f64, @floatFromInt(enter_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// @as(f64, @floatFromInt(enter_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// c.subvoxelsToVoxels(.border_up, exit_i_sv),
// c.subvoxelsToVoxelSubvoxels(exit_i_sv),
// @as(f64, @floatFromInt(exit_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// @as(f64, @floatFromInt(exit_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// enter_i_vx,
// enter_j_vx,
// enter_k_vx,
// exit_i_vx,
// exit_j_vx,
// exit_k_vx,
// cross_i,
// cross_j,
// cross_k,
//});
cross_indices = order3(i_index, j_index, k_index, cross_i, cross_j, cross_k, &ind_buf);
for (cross_indices) |cross_index| {
current_vx[cross_index] += ray_sign.asArray()[cross_index];
const voxel = vm.Vector3Int.initArray(current_vx);
if (self.isSolid(voxel)) {
return .{ .voxel = voxel };
}
}
}
enter_i_sv = exit_i_sv;
@@ -444,33 +596,141 @@ pub fn raycast(self: *const Chunks, origin_sv: vm.Vector3Int, ray_sv: vm.Vector3
exit_i_sv = oi + di;
exit_di_sv = exit_i_sv - oi;
exit_jdi_sv = oj * di + exit_di_sv * dj;
exit_kdi_sv = ok * di + exit_di_sv * dk;
exit_jdi_sv = @as(i64, oj) * @as(i64, di) + @as(i64, exit_di_sv) * @as(i64, dj);
exit_kdi_sv = @as(i64, ok) * @as(i64, di) + @as(i64, exit_di_sv) * @as(i64, dk);
exit_i_vx = @divFloor(exit_i_sv - ray_positive.asArray()[i_index], c.sv_per_vx);
exit_j_vx = @divFloor(exit_jdi_sv - ray_positive.asArray()[j_index], c.sv_per_vx * di);
exit_k_vx = @divFloor(exit_kdi_sv - ray_positive.asArray()[k_index], c.sv_per_vx * di);
exit_i_vx = @divFloor(exit_i_sv - rpi, c.sv_per_vx);
exit_j_vx = @intCast(@divFloor(exit_jdi_sv - rpj, c.sv_per_vx * @as(i64, di)));
exit_k_vx = @intCast(@divFloor(exit_kdi_sv - rpk, c.sv_per_vx * @as(i64, di)));
std.debug.print("({d}:{X}, {d:.3}, {d:.3}) → ({d}:{X}, {d:.3}, {d:.3}) | ({d}, {d}, {d}) → ({d}, {d}, {d})\n", .{
c.subvoxelsToVoxels(.border_up, enter_i_sv),
c.subvoxelsToVoxelSubvoxels(enter_i_sv),
@as(f64, @floatFromInt(enter_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
@as(f64, @floatFromInt(enter_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
c.subvoxelsToVoxels(.border_up, exit_i_sv),
c.subvoxelsToVoxelSubvoxels(exit_i_sv),
@as(f64, @floatFromInt(exit_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
@as(f64, @floatFromInt(exit_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
enter_i_vx,
enter_j_vx,
enter_k_vx,
exit_i_vx,
exit_j_vx,
exit_k_vx,
});
cross_i = vm.unlerpInt(enter_i_sv, exit_i_sv, c.voxelsToSubvoxels(exit_i_vx + rni));
cross_j = vm.unlerpInt64(enter_jdi_sv, exit_jdi_sv, c.voxelsToSubvoxels(exit_j_vx + rnj) * @as(i64, di));
cross_k = vm.unlerpInt64(enter_kdi_sv, exit_kdi_sv, c.voxelsToSubvoxels(exit_k_vx + rnk) * @as(i64, di));
// XXX
std.debug.print("\n", .{});
//std.debug.print("({d}:{X:0>3}, {d:.3}, {d:.3}) → ({d}:{X:0>3}, {d:.3}, {d:.3}) | ({d}, {d}, {d}) → ({d}, {d}, {d}) | × ({d:.3}, {d:.3}, {d:.3})\n", .{
// c.subvoxelsToVoxels(.border_up, enter_i_sv),
// c.subvoxelsToVoxelSubvoxels(enter_i_sv),
// @as(f64, @floatFromInt(enter_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// @as(f64, @floatFromInt(enter_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// c.subvoxelsToVoxels(.border_up, exit_i_sv),
// c.subvoxelsToVoxelSubvoxels(exit_i_sv),
// @as(f64, @floatFromInt(exit_jdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// @as(f64, @floatFromInt(exit_kdi_sv)) / @as(f64, @floatFromInt(di * c.sv_per_vx)),
// enter_i_vx,
// enter_j_vx,
// enter_k_vx,
// exit_i_vx,
// exit_j_vx,
// exit_k_vx,
// cross_i,
// cross_j,
// cross_k,
//});
cross_indices = order3(i_index, j_index, k_index, cross_i, cross_j, cross_k, &ind_buf);
for (cross_indices) |cross_index| {
current_vx[cross_index] += ray_sign.asArray()[cross_index];
const voxel = vm.Vector3Int.initArray(current_vx);
if (self.isSolid(voxel)) {
return .{ .voxel = voxel };
}
}
//std.debug.print("\n", .{});
_ = self;
return null;
}
fn order3(i: usize, j: usize, k: usize, cross_i: f32, cross_j: f32, cross_k: f32, buf: *[3]usize) []usize {
if (cross_i >= 0 and cross_i < 1) {
if (cross_j >= 0 and cross_j < 1) {
if (cross_k >= 0 and cross_k < 1) {
if (cross_i < cross_j and cross_i < cross_k) {
if (cross_j < cross_k) {
// Crossed I, J, K
buf.* = .{ i, j, k };
return buf[0..3];
} else {
// Crossed I, K, J
buf.* = .{ i, k, j };
return buf[0..3];
}
} else if (cross_j < cross_k) {
if (cross_i < cross_k) {
// Crossed J, I, K
buf.* = .{ j, i, k };
return buf[0..3];
} else {
// Crossed J, K, I
buf.* = .{ j, k, i };
return buf[0..3];
}
} else {
if (cross_i < cross_j) {
// Crossed K, I, J
buf.* = .{ k, i, j };
return buf[0..3];
} else {
// Crossed K, J, I
buf.* = .{ k, j, i };
return buf[0..3];
}
}
} else {
if (cross_i < cross_j) {
// Crossed I, J
buf.* = .{ i, j, undefined };
return buf[0..2];
} else {
// Crossed J, I
buf.* = .{ j, i, undefined };
return buf[0..2];
}
}
} else {
if (cross_k >= 0 and cross_k < 1) {
if (cross_i < cross_k) {
// Crossed I, K
buf.* = .{ i, k, undefined };
return buf[0..2];
} else {
// Crossed K, I
buf.* = .{ k, i, undefined };
return buf[0..2];
}
} else {
// Crossed I
buf.* = .{ i, undefined, undefined };
return buf[0..1];
}
}
} else {
if (cross_j >= 0 and cross_j < 1) {
if (cross_k >= 0 and cross_k < 1) {
if (cross_j < cross_k) {
// Crossed J, K
buf.* = .{ j, k, undefined };
return buf[0..2];
} else {
// Crossed K, J
buf.* = .{ k, j, undefined };
return buf[0..2];
}
} else {
// Crossed J
buf.* = .{ j, undefined, undefined };
return buf[0..1];
}
} else {
if (cross_k >= 0 and cross_k < 1) {
// Crossed K
buf.* = .{ k, undefined, undefined };
return buf[0..1];
} else {
// Crossed nothing
buf.* = undefined;
return buf[0..0];
}
}
}
}

View File

@@ -721,8 +721,7 @@ pub fn onMouseMove(self: *Game, dx: f32, dy: f32) void {
}
pub fn onMouseDown(self: *Game, button: glfw.MouseButton) void {
_ = self;
_ = button;
self.player.onMouseDown(button, self);
}
pub fn onMouseUp(self: *Game, button: glfw.MouseButton) void {

View File

@@ -8,6 +8,7 @@ const vm = @import("vecmath");
const Blocks = @import("assets/Blocks.zig");
const Chunks = @import("Chunks.zig");
const Game = @import("Game.zig");
const Iterator2 = math.Iterator2;
const AxisState = enum {
@@ -175,6 +176,7 @@ mouse_sensitivity: f32 = 0.0003,
vertical_fov_deg: f32 = 80,
movement_state: MovementState,
maybe_raycast_hit: ?Chunks.RaycastHit = null,
pub const camera_height_vx = 1.62;
@@ -225,19 +227,38 @@ pub fn onMouseMove(self: *Player, dx: f32, dy: f32) void {
self.yaw_turns = @mod(self.yaw_turns - dx * self.mouse_sensitivity, 1);
}
pub fn onMouseDown(self: *Player, button: glfw.MouseButton, game: *Game) void {
if (self.maybe_raycast_hit) |raycast_hit| {
switch (button) {
.left => {
game.chunks.destroyVoxelAt(
raycast_hit.voxel,
game.engine,
&game.blocks,
game.allocator,
) catch |err| {
std.log.err("Error while destroying voxel {f}: {}", .{ raycast_hit.voxel, err });
};
},
else => {},
}
}
}
pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
defer self.resetAllButtons();
//const raycast_origin_sv = self.position_sv
// .add(.init(0, 0, @intFromFloat(@round(c.sv_per_vx * camera_height_vx))));
//const raycast_ray_sv = vm.Vector3
// .init(0, raycast_length_sv, 0)
// .rotate(.mulQuaternion(
// .initRotation(.XY, self.yaw_turns),
// .initRotation(.YZ, self.pitch_turns),
// ))
// .asVector3Int();
//const raycast_hit = chunks.raycast(raycast_origin_sv, raycast_ray_sv);
const raycast_origin_sv = self.position_sv
.add(.init(0, 0, @intFromFloat(@round(c.sv_per_vx * camera_height_vx))));
const raycast_ray_sv = vm.Vector3
.init(0, raycast_length_sv, 0)
.rotate(.mulQuaternion(
.initRotation(.XY, self.yaw_turns),
.initRotation(.YZ, self.pitch_turns),
))
.round()
.asInt();
self.maybe_raycast_hit = chunks.raycast(raycast_origin_sv, raycast_ray_sv);
// --- GATHER INPUTS -------------------------------------------------------