Blocks and chunks
This commit is contained in:
238
src/assets/Chunk.zig
Normal file
238
src/assets/Chunk.zig
Normal file
@@ -0,0 +1,238 @@
|
||||
const Chunk = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const math = @import("../math.zig");
|
||||
|
||||
const Blocks = @import("Blocks.zig");
|
||||
const CommandBuffer = @import("../engine/CommandBuffer.zig").CommandBuffer;
|
||||
const Engine = @import("../engine/Engine.zig");
|
||||
const Game = @import("../Game.zig");
|
||||
const GenericBuffer = @import("../engine/GenericBuffer.zig").GenericBuffer;
|
||||
|
||||
const Matrix4x4 = math.Matrix4x4;
|
||||
const ObjectUniformsBuffer = GenericBuffer(void, Game.ObjectUniforms);
|
||||
const Vector3 = math.Vector3;
|
||||
|
||||
pub const chunk_size = 16;
|
||||
|
||||
const initial_capacity = 256;
|
||||
|
||||
blocks: [chunk_size][chunk_size][chunk_size]Blocks.Id,
|
||||
origin: Vector3,
|
||||
descriptor_set: vk.DescriptorSet,
|
||||
object_buffer: ObjectUniformsBuffer,
|
||||
object_count: u32,
|
||||
|
||||
pub const InitInfo = struct {
|
||||
origin: Vector3,
|
||||
descriptor_pool: vk.DescriptorPool,
|
||||
per_batch_descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
};
|
||||
|
||||
pub fn init(engine: *Engine, init_info: InitInfo) !Chunk {
|
||||
const descriptor_set = try engine.allocateDescriptorSet(.{
|
||||
.descriptor_pool = init_info.descriptor_pool,
|
||||
.set_layout = init_info.per_batch_descriptor_set_layout,
|
||||
});
|
||||
errdefer engine.freeDescriptorSet(init_info.descriptor_pool, descriptor_set);
|
||||
|
||||
var object_buffer: ObjectUniformsBuffer = try .init(engine, .{
|
||||
.usage = .storage,
|
||||
.target_queue = .graphics,
|
||||
.array_capacity = initial_capacity,
|
||||
});
|
||||
errdefer object_buffer.deinit(engine);
|
||||
|
||||
try engine.updateDescriptorSets(.{
|
||||
.writes = &.{
|
||||
.{
|
||||
.dst_set = descriptor_set,
|
||||
.dst_binding = 0,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .storage_buffer,
|
||||
.descriptor_infos = .{
|
||||
.buffer = &.{
|
||||
.{
|
||||
.buffer = object_buffer.buffer,
|
||||
.offset = 0,
|
||||
.range = vk.WHOLE_SIZE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return .{
|
||||
.blocks = .{.{[_]Blocks.Id{.air} ** chunk_size} ** chunk_size} ** chunk_size,
|
||||
.origin = init_info.origin,
|
||||
.descriptor_set = descriptor_set,
|
||||
.object_buffer = object_buffer,
|
||||
.object_count = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Chunk, engine: *Engine, descriptor_pool: vk.DescriptorPool) void {
|
||||
self.object_buffer.deinit(engine);
|
||||
engine.freeDescriptorSet(descriptor_pool, self.descriptor_set);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, temp_allocator: std.mem.Allocator) !void {
|
||||
var object_count: u32 = 0;
|
||||
|
||||
for (self.blocks) |plane| {
|
||||
for (plane) |row| {
|
||||
for (row) |id| {
|
||||
const block = blocks.getBlock(id).?;
|
||||
object_count += @intFromBool(block.positive_x != .empty);
|
||||
object_count += @intFromBool(block.negative_x != .empty);
|
||||
object_count += @intFromBool(block.positive_y != .empty);
|
||||
object_count += @intFromBool(block.negative_y != .empty);
|
||||
object_count += @intFromBool(block.positive_z != .empty);
|
||||
object_count += @intFromBool(block.negative_z != .empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self.object_buffer.array_capacity < object_count) {
|
||||
const desired_capacity = std.math.ceilPowerOfTwoAssert(u32, object_count);
|
||||
const new_object_buffer: ObjectUniformsBuffer = try .init(engine, .{
|
||||
.usage = .storage,
|
||||
.target_queue = .graphics,
|
||||
.array_capacity = desired_capacity,
|
||||
});
|
||||
|
||||
try engine.updateDescriptorSets(.{
|
||||
.writes = &.{
|
||||
.{
|
||||
.dst_set = self.descriptor_set,
|
||||
.dst_binding = 0,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .storage_buffer,
|
||||
.descriptor_infos = .{
|
||||
.buffer = &.{
|
||||
.{
|
||||
.buffer = new_object_buffer.buffer,
|
||||
.offset = 0,
|
||||
.range = vk.WHOLE_SIZE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
self.object_buffer.deinit(engine);
|
||||
self.object_buffer = new_object_buffer;
|
||||
}
|
||||
|
||||
const uniforms = try temp_allocator.alloc(Game.ObjectUniforms, object_count);
|
||||
var object_i: usize = 0;
|
||||
defer temp_allocator.free(uniforms);
|
||||
|
||||
for (self.blocks, 0..) |plane, iz| {
|
||||
const fz: f32 = @floatFromInt(iz);
|
||||
for (plane, 0..) |row, iy| {
|
||||
const fy: f32 = @floatFromInt(iy);
|
||||
for (row, 0..) |id, ix| {
|
||||
const fx: f32 = @floatFromInt(ix);
|
||||
const block = blocks.getBlock(id).?;
|
||||
|
||||
const center = Vector3.add(self.origin, .init(fx, fy, fz));
|
||||
const cx, const cy, const cz = center.asArray();
|
||||
|
||||
if (block.positive_x != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
cx + 0.5, cy, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.positive_x);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.negative_x != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
0, -1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
-1, 0, 0, 0,
|
||||
cx - 0.5, cy, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.negative_x);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.positive_y != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
-1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
cx, cy + 0.5, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.positive_y);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.negative_y != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, -1, 0, 0,
|
||||
cx, cy - 0.5, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.negative_y);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.positive_z != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
cx, cy, cz + 0.5, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.positive_z);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.negative_z != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
cx, cy, cz - 0.5, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.negative_z);
|
||||
object_i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.assert(object_i == uniforms.len);
|
||||
|
||||
try self.object_buffer.write(engine, .{ .elements = uniforms });
|
||||
self.object_count = object_count;
|
||||
}
|
||||
|
||||
pub fn draw(self: *const Chunk, layout: vk.PipelineLayout, command_buffer: CommandBuffer(.graphics, .transient)) void {
|
||||
command_buffer.bindDescriptorSets(.graphics, layout, 1, &.{self.descriptor_set}, &.{});
|
||||
command_buffer.drawIndexed(.{ .index_count = 6, .instance_count = self.object_count });
|
||||
}
|
||||
Reference in New Issue
Block a user