Separate out Chunks-related code, "fix" collisions to be less broken
This commit is contained in:
286
src/Chunks.zig
Normal file
286
src/Chunks.zig
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
const Chunks = @This();
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const c = @import("const.zig");
|
||||||
|
const math = @import("math.zig");
|
||||||
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const Blocks = @import("assets/Blocks.zig");
|
||||||
|
const Chunk = @import("assets/Chunk.zig");
|
||||||
|
const Engine = @import("engine/Engine.zig");
|
||||||
|
const Iterator2 = math.Iterator2;
|
||||||
|
const Vector2Int = math.Vector2Int;
|
||||||
|
const Vector3Int = math.Vector3Int;
|
||||||
|
|
||||||
|
chunks: std.AutoHashMapUnmanaged([3]i16, Chunk),
|
||||||
|
|
||||||
|
const SweepHit = struct {
|
||||||
|
normal_frac: Vector3Int,
|
||||||
|
projected_distance_sv: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
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| {
|
||||||
|
chunk.deinit(engine, descriptor_pool);
|
||||||
|
}
|
||||||
|
self.chunks.deinit(allocator);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getVoxelAt(self: *const Chunks, vx: Vector3Int) ?Blocks.Id {
|
||||||
|
const min_ck = Vector3Int.initScalar(std.math.minInt(i16));
|
||||||
|
const max_ck = Vector3Int.initScalar(std.math.maxInt(i16));
|
||||||
|
const ck = vx.divScalar(c.vx_per_ck);
|
||||||
|
if (@reduce(.Or, (ck.vector < min_ck.vector) | (ck.vector > max_ck.vector))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.chunks.get(.{
|
||||||
|
@intCast(ck.getX()),
|
||||||
|
@intCast(ck.getY()),
|
||||||
|
@intCast(ck.getZ()),
|
||||||
|
})) |chunk| {
|
||||||
|
const ckvx = vx.modScalar(c.vx_per_ck);
|
||||||
|
return chunk.blocks[@intCast(ckvx.getZ())][@intCast(ckvx.getY())][@intCast(ckvx.getX())];
|
||||||
|
} else {
|
||||||
|
return .air;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isSolid(self: *const Chunks, vx: 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: Vector3Int, max_sv: Vector3Int, distance_sv: i32) ?SweepHit {
|
||||||
|
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.getX());
|
||||||
|
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.getY());
|
||||||
|
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.getX());
|
||||||
|
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_sv.getY());
|
||||||
|
|
||||||
|
const start_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.getZ()) - 1;
|
||||||
|
const end_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.getZ() - distance_sv);
|
||||||
|
|
||||||
|
var z_vx: i32 = start_z_vx;
|
||||||
|
while (z_vx >= end_z_vx) : (z_vx -= 1) {
|
||||||
|
const z_sv = c.voxelsToSubvoxels(z_vx + 1);
|
||||||
|
var it = Iterator2(i32).init(.{
|
||||||
|
.min = .{ min_x_vx, min_y_vx },
|
||||||
|
.max = .{ max_x_vx, max_y_vx },
|
||||||
|
});
|
||||||
|
while (it.next()) |xy_vx| {
|
||||||
|
const x_vx, const y_vx = xy_vx;
|
||||||
|
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.projected_distance_sv = distance_sv - (min_sv.getZ() - z_sv),
|
||||||
|
.normal_frac = .unit_z_frac,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sweepCastUp(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int, distance_sv: i32) ?SweepHit {
|
||||||
|
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_sv.getX());
|
||||||
|
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_sv.getY());
|
||||||
|
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_sv.getX());
|
||||||
|
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_sv.getY());
|
||||||
|
|
||||||
|
const start_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.getZ()) + 1;
|
||||||
|
const end_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.getZ() + distance_sv);
|
||||||
|
|
||||||
|
var z_vx: i32 = start_z_vx;
|
||||||
|
while (z_vx <= end_z_vx) : (z_vx += 1) {
|
||||||
|
const z_sv = c.voxelsToSubvoxels(z_vx);
|
||||||
|
var it = Iterator2(i32).init(.{
|
||||||
|
.min = .{ min_x_vx, min_y_vx },
|
||||||
|
.max = .{ max_x_vx, max_y_vx },
|
||||||
|
});
|
||||||
|
while (it.next()) |xy_vx| {
|
||||||
|
const x_vx, const y_vx = xy_vx;
|
||||||
|
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.projected_distance_sv = distance_sv - (z_sv - max_sv.getZ()),
|
||||||
|
.normal_frac = .unit_nz_frac,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sweepCastHorizontal(self: *const Chunks, min_sv: Vector3Int, max_sv: Vector3Int, ray_sv: Vector2Int) ?SweepHit {
|
||||||
|
const min_z_vx = c.subvoxelsToVoxels(.border_up, min_sv.getZ());
|
||||||
|
const max_z_vx = c.subvoxelsToVoxels(.border_down, max_sv.getZ());
|
||||||
|
|
||||||
|
var hit: ?SweepHit = null;
|
||||||
|
var hit_distance_squared = std.math.inf(f32);
|
||||||
|
|
||||||
|
const fdydx: f32 = @as(f32, @floatFromInt(ray_sv.getY())) / @as(f32, @floatFromInt(ray_sv.getX()));
|
||||||
|
const fdxdy: f32 = @as(f32, @floatFromInt(ray_sv.getX())) / @as(f32, @floatFromInt(ray_sv.getY()));
|
||||||
|
|
||||||
|
// Positive X
|
||||||
|
if (ray_sv.getX() > 0) {
|
||||||
|
const x0_sv = max_sv.getX();
|
||||||
|
const y0_sv = min_sv.getY();
|
||||||
|
const y1_sv = max_sv.getY();
|
||||||
|
|
||||||
|
const start_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv) + 1;
|
||||||
|
const end_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv + ray_sv.getX());
|
||||||
|
|
||||||
|
var x_vx: i32 = start_x_vx;
|
||||||
|
px: while (x_vx <= end_x_vx) : (x_vx += 1) {
|
||||||
|
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 max_y_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
|
||||||
|
var it = Iterator2(i32).init(.{
|
||||||
|
.min = .{ min_y_vx, min_z_vx },
|
||||||
|
.max = .{ max_y_vx, max_z_vx },
|
||||||
|
});
|
||||||
|
while (it.next()) |yz_vx| {
|
||||||
|
const y_vx, const z_vx = yz_vx;
|
||||||
|
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
|
||||||
|
|
||||||
|
const dx = x_sv - x0_sv;
|
||||||
|
const fdx: f32 = @floatFromInt(dx);
|
||||||
|
const fdy: f32 = fdx * fdydx;
|
||||||
|
|
||||||
|
hit = .{
|
||||||
|
.projected_distance_sv = ray_sv.getX() - dx,
|
||||||
|
.normal_frac = .unit_nx_frac,
|
||||||
|
};
|
||||||
|
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 });
|
||||||
|
|
||||||
|
break :px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative X
|
||||||
|
if (ray_sv.getX() < 0) {
|
||||||
|
const x0_sv = min_sv.getX();
|
||||||
|
const y0_sv = min_sv.getY();
|
||||||
|
const y1_sv = max_sv.getY();
|
||||||
|
|
||||||
|
const start_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv) - 1;
|
||||||
|
const end_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv + ray_sv.getX());
|
||||||
|
|
||||||
|
var x_vx: i32 = start_x_vx;
|
||||||
|
nx: while (x_vx >= end_x_vx) : (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 max_y_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
|
||||||
|
var it = Iterator2(i32).init(.{
|
||||||
|
.min = .{ min_y_vx, min_z_vx },
|
||||||
|
.max = .{ max_y_vx, max_z_vx },
|
||||||
|
});
|
||||||
|
while (it.next()) |yz_vx| {
|
||||||
|
const y_vx, const z_vx = yz_vx;
|
||||||
|
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
|
||||||
|
|
||||||
|
const dx = x_sv - x0_sv;
|
||||||
|
const fdx: f32 = @floatFromInt(dx);
|
||||||
|
const fdy: f32 = fdx * fdydx;
|
||||||
|
|
||||||
|
hit = .{
|
||||||
|
.projected_distance_sv = -(ray_sv.getX() - dx),
|
||||||
|
.normal_frac = .unit_x_frac,
|
||||||
|
};
|
||||||
|
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 });
|
||||||
|
|
||||||
|
break :nx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Positive Y
|
||||||
|
if (ray_sv.getY() > 0) {
|
||||||
|
const y0_sv = max_sv.getY();
|
||||||
|
const x0_sv = min_sv.getX();
|
||||||
|
const x1_sv = max_sv.getX();
|
||||||
|
|
||||||
|
const start_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv) + 1;
|
||||||
|
const end_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv + ray_sv.getY());
|
||||||
|
|
||||||
|
var y_vx = start_y_vx;
|
||||||
|
py: while (y_vx <= end_y_vx) : (y_vx += 1) {
|
||||||
|
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 max_x_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
|
||||||
|
var it = Iterator2(i32).init(.{
|
||||||
|
.min = .{ min_x_vx, min_z_vx },
|
||||||
|
.max = .{ max_x_vx, max_z_vx },
|
||||||
|
});
|
||||||
|
while (it.next()) |xz_vx| {
|
||||||
|
const x_vx, const z_vx = xz_vx;
|
||||||
|
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
|
||||||
|
|
||||||
|
const dy = y_sv - y0_sv;
|
||||||
|
const fdy: f32 = @floatFromInt(dy);
|
||||||
|
const fdx: f32 = fdy * fdxdy;
|
||||||
|
|
||||||
|
const this_hit_distance_squared = fdx * fdx + fdy * fdy;
|
||||||
|
if (this_hit_distance_squared < hit_distance_squared) {
|
||||||
|
hit = .{
|
||||||
|
.projected_distance_sv = ray_sv.getY() - dy,
|
||||||
|
.normal_frac = .unit_ny_frac,
|
||||||
|
};
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
break :py;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negative Y
|
||||||
|
if (ray_sv.getY() < 0.0) {
|
||||||
|
const y0_sv = min_sv.getY();
|
||||||
|
const x0_sv = min_sv.getX();
|
||||||
|
const x1_sv = max_sv.getX();
|
||||||
|
|
||||||
|
const start_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv) - 1;
|
||||||
|
const end_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv + ray_sv.getY());
|
||||||
|
|
||||||
|
var y_vx = start_y_vx;
|
||||||
|
ny: while (y_vx >= end_y_vx) : (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 max_x_vx = c.subvoxelsToVoxels(.border_down, math.wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
|
||||||
|
var it = Iterator2(i32).init(.{
|
||||||
|
.min = .{ min_x_vx, min_z_vx },
|
||||||
|
.max = .{ max_x_vx, max_z_vx },
|
||||||
|
});
|
||||||
|
while (it.next()) |xz_vx| {
|
||||||
|
const x_vx, const z_vx = xz_vx;
|
||||||
|
if (!self.isSolid(.init(x_vx, y_vx, z_vx))) continue;
|
||||||
|
|
||||||
|
const dy = y_sv - y0_sv;
|
||||||
|
const fdy: f32 = @floatFromInt(dy);
|
||||||
|
const fdx: f32 = fdy * fdxdy;
|
||||||
|
|
||||||
|
const this_hit_distance_squared = fdx * fdx + fdy * fdy;
|
||||||
|
if (this_hit_distance_squared < hit_distance_squared) {
|
||||||
|
hit = .{
|
||||||
|
.projected_distance_sv = -(ray_sv.getY() - dy),
|
||||||
|
.normal_frac = .unit_y_frac,
|
||||||
|
};
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
break :ny;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
13
src/Game.zig
13
src/Game.zig
@@ -10,6 +10,7 @@ const worldgen = @import("worldgen.zig");
|
|||||||
|
|
||||||
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 Chunks = @import("Chunks.zig");
|
||||||
const CommandBuffer = @import("engine/CommandBuffer.zig");
|
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;
|
||||||
@@ -50,7 +51,7 @@ deferred_command_buffers: std.ArrayList(CommandBuffer),
|
|||||||
blocks: Blocks,
|
blocks: Blocks,
|
||||||
materials: Materials,
|
materials: Materials,
|
||||||
textures: Textures,
|
textures: Textures,
|
||||||
chunks: std.AutoHashMapUnmanaged([3]i16, Chunk),
|
chunks: Chunks,
|
||||||
skybox: Skybox,
|
skybox: Skybox,
|
||||||
|
|
||||||
player: Player,
|
player: Player,
|
||||||
@@ -659,7 +660,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
|||||||
.blocks = blocks,
|
.blocks = blocks,
|
||||||
.materials = materials,
|
.materials = materials,
|
||||||
.textures = textures,
|
.textures = textures,
|
||||||
.chunks = chunks,
|
.chunks = .{ .chunks = chunks },
|
||||||
.skybox = skybox,
|
.skybox = skybox,
|
||||||
|
|
||||||
.player = .init(player_position_sv, 0, 0),
|
.player = .init(player_position_sv, 0, 0),
|
||||||
@@ -677,11 +678,7 @@ pub fn deinit(self: *Game) void {
|
|||||||
self.vertex_buffer.deinit(self.engine);
|
self.vertex_buffer.deinit(self.engine);
|
||||||
self.index_buffer.deinit(self.engine);
|
self.index_buffer.deinit(self.engine);
|
||||||
|
|
||||||
var it = self.chunks.valueIterator();
|
self.chunks.deinit(self.engine, self.descriptor_pool, self.allocator);
|
||||||
while (it.next()) |chunk| {
|
|
||||||
chunk.deinit(self.engine, self.descriptor_pool);
|
|
||||||
}
|
|
||||||
self.chunks.deinit(self.allocator);
|
|
||||||
self.skybox.deinit(self.engine);
|
self.skybox.deinit(self.engine);
|
||||||
|
|
||||||
self.global_uniforms.deinit(self.engine);
|
self.global_uniforms.deinit(self.engine);
|
||||||
@@ -889,7 +886,7 @@ fn render(self: *Game) !void {
|
|||||||
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
||||||
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.global_descriptor_set, null);
|
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.global_descriptor_set, null);
|
||||||
|
|
||||||
var it = self.chunks.valueIterator();
|
var it = self.chunks.chunks.valueIterator();
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
chunk.draw(self.pipeline_layout, command_buffer);
|
chunk.draw(self.pipeline_layout, command_buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
295
src/Player.zig
295
src/Player.zig
@@ -6,7 +6,7 @@ const glfw = @import("zglfw");
|
|||||||
const math = @import("math.zig");
|
const math = @import("math.zig");
|
||||||
|
|
||||||
const Blocks = @import("assets/Blocks.zig");
|
const Blocks = @import("assets/Blocks.zig");
|
||||||
const Chunk = @import("assets/Chunk.zig");
|
const Chunks = @import("Chunks.zig");
|
||||||
const Iterator2 = math.Iterator2;
|
const Iterator2 = math.Iterator2;
|
||||||
const Vector2 = math.Vector2;
|
const Vector2 = math.Vector2;
|
||||||
const Vector3 = math.Vector3;
|
const Vector3 = math.Vector3;
|
||||||
@@ -226,7 +226,7 @@ pub fn onMouseMove(self: *Player, dx: f32, dy: f32) void {
|
|||||||
self.yaw_rad = @mod(self.yaw_rad - dx * self.mouse_sensitivity, std.math.tau);
|
self.yaw_rad = @mod(self.yaw_rad - dx * self.mouse_sensitivity, std.math.tau);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) void {
|
pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
|
||||||
defer self.resetAllButtons();
|
defer self.resetAllButtons();
|
||||||
|
|
||||||
// --- GATHER INPUTS -------------------------------------------------------
|
// --- GATHER INPUTS -------------------------------------------------------
|
||||||
@@ -272,17 +272,21 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
|
|||||||
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;
|
||||||
|
var min_sv = position_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
||||||
|
var max_sv = position_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
||||||
|
|
||||||
if (vertical_displacement_sv > 0) {
|
if (vertical_displacement_sv > 0) {
|
||||||
if (sweepCastUp(position_sv, vertical_displacement_sv, chunks)) |hit| {
|
if (chunks.sweepCastUp(min_sv, max_sv, vertical_displacement_sv)) |hit| {
|
||||||
vertical_displacement_sv -= hit.projected_distance_sv;
|
vertical_displacement_sv -= hit.projected_distance_sv;
|
||||||
}
|
}
|
||||||
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
|
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
|
||||||
|
min_sv = .add(min_sv, .init(0, 0, vertical_displacement_sv));
|
||||||
|
max_sv = .add(max_sv, .init(0, 0, vertical_displacement_sv));
|
||||||
}
|
}
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < 2) : (i += 1) {
|
while (i < 2) : (i += 1) {
|
||||||
if (sweepCastHorizontal(position_sv, horizontal_displacement_sv, chunks)) |hit| {
|
if (chunks.sweepCastHorizontal(min_sv, max_sv, horizontal_displacement_sv)) |hit| {
|
||||||
const adjustment = hit.normal_frac
|
const adjustment = hit.normal_frac
|
||||||
.asVector2Int()
|
.asVector2Int()
|
||||||
.mulScalarFrac(hit.projected_distance_sv);
|
.mulScalarFrac(hit.projected_distance_sv);
|
||||||
@@ -306,7 +310,9 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
|
|||||||
position_sv = .add(position_sv, horizontal_displacement_sv.asVector3Int(0));
|
position_sv = .add(position_sv, horizontal_displacement_sv.asVector3Int(0));
|
||||||
|
|
||||||
if (vertical_displacement_sv < 0.0) {
|
if (vertical_displacement_sv < 0.0) {
|
||||||
if (sweepCastDown(position_sv, -vertical_displacement_sv, chunks)) |hit| {
|
min_sv = .add(min_sv, horizontal_displacement_sv.asVector3Int(0));
|
||||||
|
max_sv = .add(max_sv, horizontal_displacement_sv.asVector3Int(0));
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
|
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
|
||||||
@@ -317,251 +323,6 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SweepHit = struct {
|
|
||||||
normal_frac: Vector3Int,
|
|
||||||
projected_distance_sv: i32,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn sweepCastDown(origin_sv: Vector3Int, distance_sv: i32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
|
||||||
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
|
||||||
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
|
||||||
|
|
||||||
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getX());
|
|
||||||
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getY());
|
|
||||||
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getX());
|
|
||||||
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getY());
|
|
||||||
|
|
||||||
const start_z_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getZ()) - 1;
|
|
||||||
const end_z_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getZ() - distance_sv);
|
|
||||||
|
|
||||||
var z_vx: i32 = start_z_vx;
|
|
||||||
while (z_vx >= end_z_vx) : (z_vx -= 1) {
|
|
||||||
const z_sv = c.voxelsToSubvoxels(z_vx + 1);
|
|
||||||
var it = Iterator2(i32).init(.{
|
|
||||||
.min = .{ min_x_vx, min_y_vx },
|
|
||||||
.max = .{ max_x_vx, max_y_vx },
|
|
||||||
});
|
|
||||||
while (it.next()) |xy_vx| {
|
|
||||||
const x_vx, const y_vx = xy_vx;
|
|
||||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.projected_distance_sv = distance_sv - (min_origin_sv.getZ() - z_sv),
|
|
||||||
.normal_frac = .unit_z_frac,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sweepCastUp(origin_sv: Vector3Int, distance_sv: i32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
|
||||||
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
|
||||||
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
|
||||||
|
|
||||||
const min_x_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getX());
|
|
||||||
const min_y_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getY());
|
|
||||||
const max_x_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getX());
|
|
||||||
const max_y_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getY());
|
|
||||||
|
|
||||||
const start_z_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getZ()) + 1;
|
|
||||||
const end_z_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getZ() + distance_sv);
|
|
||||||
|
|
||||||
var z_vx: i32 = start_z_vx;
|
|
||||||
while (z_vx <= end_z_vx) : (z_vx += 1) {
|
|
||||||
const z_sv = c.voxelsToSubvoxels(z_vx);
|
|
||||||
var it = Iterator2(i32).init(.{
|
|
||||||
.min = .{ min_x_vx, min_y_vx },
|
|
||||||
.max = .{ max_x_vx, max_y_vx },
|
|
||||||
});
|
|
||||||
while (it.next()) |xy_vx| {
|
|
||||||
const x_vx, const y_vx = xy_vx;
|
|
||||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.projected_distance_sv = distance_sv - (z_sv - max_origin_sv.getZ()),
|
|
||||||
.normal_frac = .unit_nz_frac,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
|
||||||
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
|
||||||
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
|
||||||
|
|
||||||
const min_z_vx = c.subvoxelsToVoxels(.border_up, min_origin_sv.getZ());
|
|
||||||
const max_z_vx = c.subvoxelsToVoxels(.border_down, max_origin_sv.getZ());
|
|
||||||
|
|
||||||
var hit: ?SweepHit = null;
|
|
||||||
var hit_distance_squared = std.math.inf(f32);
|
|
||||||
|
|
||||||
const fdydx: f32 = @as(f32, @floatFromInt(ray_sv.getY())) / @as(f32, @floatFromInt(ray_sv.getX()));
|
|
||||||
const fdxdy: f32 = @as(f32, @floatFromInt(ray_sv.getX())) / @as(f32, @floatFromInt(ray_sv.getY()));
|
|
||||||
|
|
||||||
// Positive X
|
|
||||||
if (ray_sv.getX() > 0) {
|
|
||||||
const x0_sv = max_origin_sv.getX();
|
|
||||||
const y0_sv = min_origin_sv.getY();
|
|
||||||
const y1_sv = max_origin_sv.getY();
|
|
||||||
|
|
||||||
const start_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv) + 1;
|
|
||||||
const end_x_vx = c.subvoxelsToVoxels(.border_down, x0_sv + ray_sv.getX());
|
|
||||||
|
|
||||||
var x_vx: i32 = start_x_vx;
|
|
||||||
px: while (x_vx <= end_x_vx) : (x_vx += 1) {
|
|
||||||
const x_sv = c.voxelsToSubvoxels(x_vx);
|
|
||||||
const min_y_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
|
|
||||||
const max_y_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
|
|
||||||
var it = Iterator2(i32).init(.{
|
|
||||||
.min = .{ min_y_vx, min_z_vx },
|
|
||||||
.max = .{ max_y_vx, max_z_vx },
|
|
||||||
});
|
|
||||||
while (it.next()) |yz_vx| {
|
|
||||||
const y_vx, const z_vx = yz_vx;
|
|
||||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
|
||||||
|
|
||||||
const dx = x_sv - x0_sv;
|
|
||||||
const fdx: f32 = @floatFromInt(dx);
|
|
||||||
const fdy: f32 = fdx * fdydx;
|
|
||||||
|
|
||||||
hit = .{
|
|
||||||
.projected_distance_sv = ray_sv.getX() - dx,
|
|
||||||
.normal_frac = .unit_nx_frac,
|
|
||||||
};
|
|
||||||
hit_distance_squared = fdx * fdx + fdy * fdy;
|
|
||||||
std.debug.print("+X fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, hit_distance_squared });
|
|
||||||
|
|
||||||
break :px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Negative X
|
|
||||||
if (ray_sv.getX() < 0) {
|
|
||||||
const x0_sv = min_origin_sv.getX();
|
|
||||||
const y0_sv = min_origin_sv.getY();
|
|
||||||
const y1_sv = max_origin_sv.getY();
|
|
||||||
|
|
||||||
const start_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv) - 1;
|
|
||||||
const end_x_vx = c.subvoxelsToVoxels(.border_up, x0_sv + ray_sv.getX());
|
|
||||||
|
|
||||||
var x_vx: i32 = start_x_vx;
|
|
||||||
nx: while (x_vx >= end_x_vx) : (x_vx -= 1) {
|
|
||||||
const x_sv = c.voxelsToSubvoxels(x_vx + 1);
|
|
||||||
const min_y_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
|
|
||||||
const max_y_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
|
|
||||||
var it = Iterator2(i32).init(.{
|
|
||||||
.min = .{ min_y_vx, min_z_vx },
|
|
||||||
.max = .{ max_y_vx, max_z_vx },
|
|
||||||
});
|
|
||||||
while (it.next()) |yz_vx| {
|
|
||||||
const y_vx, const z_vx = yz_vx;
|
|
||||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
|
||||||
|
|
||||||
const dx = x_sv - x0_sv;
|
|
||||||
const fdx: f32 = @floatFromInt(dx);
|
|
||||||
const fdy: f32 = fdx * fdydx;
|
|
||||||
|
|
||||||
hit = .{
|
|
||||||
.projected_distance_sv = -(ray_sv.getX() - dx),
|
|
||||||
.normal_frac = .unit_x_frac,
|
|
||||||
};
|
|
||||||
hit_distance_squared = fdx * fdx + fdy * fdy;
|
|
||||||
std.debug.print("-X fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, hit_distance_squared });
|
|
||||||
|
|
||||||
break :nx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Positive Y
|
|
||||||
if (ray_sv.getY() > 0) {
|
|
||||||
const y0_sv = max_origin_sv.getY();
|
|
||||||
const x0_sv = min_origin_sv.getX();
|
|
||||||
const x1_sv = max_origin_sv.getX();
|
|
||||||
|
|
||||||
const start_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv) + 1;
|
|
||||||
const end_y_vx = c.subvoxelsToVoxels(.border_down, y0_sv + ray_sv.getY());
|
|
||||||
|
|
||||||
var y_vx = start_y_vx;
|
|
||||||
py: while (y_vx <= end_y_vx) : (y_vx += 1) {
|
|
||||||
const y_sv = c.voxelsToSubvoxels(y_vx);
|
|
||||||
const min_x_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
|
|
||||||
const max_x_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
|
|
||||||
var it = Iterator2(i32).init(.{
|
|
||||||
.min = .{ min_x_vx, min_z_vx },
|
|
||||||
.max = .{ max_x_vx, max_z_vx },
|
|
||||||
});
|
|
||||||
while (it.next()) |xz_vx| {
|
|
||||||
const x_vx, const z_vx = xz_vx;
|
|
||||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
|
||||||
|
|
||||||
const dy = y_sv - y0_sv;
|
|
||||||
const fdy: f32 = @floatFromInt(dy);
|
|
||||||
const fdx: f32 = fdy * fdxdy;
|
|
||||||
|
|
||||||
const this_hit_distance_squared = fdx * fdx + fdy * fdy;
|
|
||||||
std.debug.print("+Y fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, this_hit_distance_squared });
|
|
||||||
if (this_hit_distance_squared < hit_distance_squared) {
|
|
||||||
hit = .{
|
|
||||||
.projected_distance_sv = ray_sv.getY() - dy,
|
|
||||||
.normal_frac = .unit_ny_frac,
|
|
||||||
};
|
|
||||||
hit_distance_squared = this_hit_distance_squared;
|
|
||||||
}
|
|
||||||
|
|
||||||
break :py;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Negative Y
|
|
||||||
if (ray_sv.getY() < 0.0) {
|
|
||||||
const y0_sv = min_origin_sv.getY();
|
|
||||||
const x0_sv = min_origin_sv.getX();
|
|
||||||
const x1_sv = max_origin_sv.getX();
|
|
||||||
|
|
||||||
const start_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv) - 1;
|
|
||||||
const end_y_vx = c.subvoxelsToVoxels(.border_up, y0_sv + ray_sv.getY());
|
|
||||||
|
|
||||||
var y_vx = start_y_vx;
|
|
||||||
ny: while (y_vx >= end_y_vx) : (y_vx -= 1) {
|
|
||||||
const y_sv = c.voxelsToSubvoxels(y_vx + 1);
|
|
||||||
const min_x_vx = c.subvoxelsToVoxels(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
|
|
||||||
const max_x_vx = c.subvoxelsToVoxels(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
|
|
||||||
var it = Iterator2(i32).init(.{
|
|
||||||
.min = .{ min_x_vx, min_z_vx },
|
|
||||||
.max = .{ max_x_vx, max_z_vx },
|
|
||||||
});
|
|
||||||
while (it.next()) |xz_vx| {
|
|
||||||
const x_vx, const z_vx = xz_vx;
|
|
||||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
|
||||||
|
|
||||||
const dy = y_sv - y0_sv;
|
|
||||||
const fdy: f32 = @floatFromInt(dy);
|
|
||||||
const fdx: f32 = fdy * fdxdy;
|
|
||||||
|
|
||||||
const this_hit_distance_squared = fdx * fdx + fdy * fdy;
|
|
||||||
std.debug.print("-Y fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, this_hit_distance_squared });
|
|
||||||
if (this_hit_distance_squared < hit_distance_squared) {
|
|
||||||
hit = .{
|
|
||||||
.projected_distance_sv = -(ray_sv.getY() - dy),
|
|
||||||
.normal_frac = .unit_y_frac,
|
|
||||||
};
|
|
||||||
hit_distance_squared = this_hit_distance_squared;
|
|
||||||
}
|
|
||||||
|
|
||||||
break :ny;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hit;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resetAllButtons(self: *Player) void {
|
fn resetAllButtons(self: *Player) void {
|
||||||
inline for (@typeInfo(Player).@"struct".fields) |field| {
|
inline for (@typeInfo(Player).@"struct".fields) |field| {
|
||||||
if (field.type == Button) {
|
if (field.type == Button) {
|
||||||
@@ -570,40 +331,6 @@ fn resetAllButtons(self: *Player) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getVoxelAt(chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk), vx: Vector3Int) ?Blocks.Id {
|
|
||||||
const min_ck = Vector3Int.initScalar(std.math.minInt(i16));
|
|
||||||
const max_ck = Vector3Int.initScalar(std.math.maxInt(i16));
|
|
||||||
const ck = vx.divScalar(c.vx_per_ck);
|
|
||||||
if (@reduce(.Or, (ck.vector < min_ck.vector) | (ck.vector > max_ck.vector))) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chunks.get(.{
|
|
||||||
@intCast(ck.getX()),
|
|
||||||
@intCast(ck.getY()),
|
|
||||||
@intCast(ck.getZ()),
|
|
||||||
})) |chunk| {
|
|
||||||
const ckvx = vx.modScalar(c.vx_per_ck);
|
|
||||||
return chunk.blocks[@intCast(ckvx.getZ())][@intCast(ckvx.getY())][@intCast(ckvx.getX())];
|
|
||||||
} else {
|
|
||||||
return .air;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn isSolid(chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk), vx: Vector3Int) bool {
|
|
||||||
const maybe_id = getVoxelAt(chunks, vx);
|
|
||||||
// NOTE `null` is considered solid, as it's out of bounds.
|
|
||||||
return maybe_id != .air;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn wideMulDivFloor(a: i32, mul: i32, div: i32) i32 {
|
|
||||||
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul), div));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn wideMulDivCeil(a: i32, mul: i32, div: i32) i32 {
|
|
||||||
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul) + @as(i64, div) - 1, div));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn sv(comptime vx: comptime_float) comptime_int {
|
inline fn sv(comptime vx: comptime_float) comptime_int {
|
||||||
return @intFromFloat(@round(vx * c.sv_per_vx));
|
return @intFromFloat(@round(vx * c.sv_per_vx));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ pub const RoundingMode = enum {
|
|||||||
/// SV to VX
|
/// SV to VX
|
||||||
pub inline fn subvoxelsToVoxels(comptime rounding_mode: RoundingMode, sv: i32) i32 {
|
pub inline fn subvoxelsToVoxels(comptime rounding_mode: RoundingMode, sv: i32) i32 {
|
||||||
return switch (rounding_mode) {
|
return switch (rounding_mode) {
|
||||||
.border_down => @divFloor(sv, sv_per_vx - 1),
|
.border_down => @divFloor(sv - 1, sv_per_vx),
|
||||||
.border_up => @divFloor(sv, sv_per_vx),
|
.border_up => @divFloor(sv, sv_per_vx),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ pub inline fn subvoxelsToVoxels(comptime rounding_mode: RoundingMode, sv: i32) i
|
|||||||
/// SV to CK
|
/// SV to CK
|
||||||
pub inline fn subvoxelsToChunks(comptime rounding_mode: RoundingMode, sv: i32) i32 {
|
pub inline fn subvoxelsToChunks(comptime rounding_mode: RoundingMode, sv: i32) i32 {
|
||||||
return switch (rounding_mode) {
|
return switch (rounding_mode) {
|
||||||
.border_down => @divFloor(sv, sv_per_ck - 1),
|
.border_down => @divFloor(sv - 1, sv_per_ck),
|
||||||
.border_up => @divFloor(sv, sv_per_ck),
|
.border_up => @divFloor(sv, sv_per_ck),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ pub inline fn voxelsToSubvoxels(vx: i32) i32 {
|
|||||||
/// VX to CK
|
/// VX to CK
|
||||||
pub inline fn voxelsToChunks(comptime rounding_mode: RoundingMode, vx: i32) i32 {
|
pub inline fn voxelsToChunks(comptime rounding_mode: RoundingMode, vx: i32) i32 {
|
||||||
return switch (rounding_mode) {
|
return switch (rounding_mode) {
|
||||||
.border_down => @divFloor(vx, vx_per_ck - 1),
|
.border_down => @divFloor(vx - 1, vx_per_ck),
|
||||||
.border_up => @divFloor(vx, vx_per_ck),
|
.border_up => @divFloor(vx, vx_per_ck),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,3 +73,11 @@ pub inline fn mulFracFrac(a: i32, b: i32) i32 {
|
|||||||
const b_wide: i64 = b;
|
const b_wide: i64 = b;
|
||||||
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 wideMulDivFloor(a: i32, mul: i32, div: i32) i32 {
|
||||||
|
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul), div));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn wideMulDivCeil(a: i32, mul: i32, div: i32) i32 {
|
||||||
|
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul) + @as(i64, div) - 1, div));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user