Blocks and chunks
This commit is contained in:
3
assets/blocks/Andesite.json
Normal file
3
assets/blocks/Andesite.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Andesite.json"
|
||||
}
|
||||
3
assets/blocks/Bricks.json
Normal file
3
assets/blocks/Bricks.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Bricks.json"
|
||||
}
|
||||
3
assets/blocks/ChiseledStoneBricks.json
Normal file
3
assets/blocks/ChiseledStoneBricks.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "ChiseledStoneBricks.json"
|
||||
}
|
||||
3
assets/blocks/CoalBlock.json
Normal file
3
assets/blocks/CoalBlock.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "CoalBlock.json"
|
||||
}
|
||||
3
assets/blocks/CoalOre.json
Normal file
3
assets/blocks/CoalOre.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "CoalOre.json"
|
||||
}
|
||||
3
assets/blocks/Cobblestone.json
Normal file
3
assets/blocks/Cobblestone.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Cobblestone.json"
|
||||
}
|
||||
3
assets/blocks/DiamondBlock.json
Normal file
3
assets/blocks/DiamondBlock.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "DiamondBlock.json"
|
||||
}
|
||||
3
assets/blocks/DiamondOre.json
Normal file
3
assets/blocks/DiamondOre.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "DiamondOre.json"
|
||||
}
|
||||
3
assets/blocks/Diorite.json
Normal file
3
assets/blocks/Diorite.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Diorite.json"
|
||||
}
|
||||
3
assets/blocks/Dirt.json
Normal file
3
assets/blocks/Dirt.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Dirt.json"
|
||||
}
|
||||
3
assets/blocks/Glass.json
Normal file
3
assets/blocks/Glass.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Glass.json"
|
||||
}
|
||||
3
assets/blocks/GoldBlock.json
Normal file
3
assets/blocks/GoldBlock.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "GoldBlock.json"
|
||||
}
|
||||
3
assets/blocks/GoldOre.json
Normal file
3
assets/blocks/GoldOre.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "GoldOre.json"
|
||||
}
|
||||
3
assets/blocks/Granite.json
Normal file
3
assets/blocks/Granite.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Granite.json"
|
||||
}
|
||||
3
assets/blocks/Gravel.json
Normal file
3
assets/blocks/Gravel.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Gravel.json"
|
||||
}
|
||||
3
assets/blocks/IronBlock.json
Normal file
3
assets/blocks/IronBlock.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "IronBlock.json"
|
||||
}
|
||||
3
assets/blocks/IronOre.json
Normal file
3
assets/blocks/IronOre.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "IronOre.json"
|
||||
}
|
||||
10
assets/blocks/OakLogX.json
Normal file
10
assets/blocks/OakLogX.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"materials": [
|
||||
"OakLogTop.json",
|
||||
"OakLogTop.json",
|
||||
"OakLog.json",
|
||||
"OakLog.json",
|
||||
"OakLog.json",
|
||||
"OakLog.json"
|
||||
]
|
||||
}
|
||||
10
assets/blocks/OakLogY.json
Normal file
10
assets/blocks/OakLogY.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"materials": [
|
||||
"OakLog.json",
|
||||
"OakLog.json",
|
||||
"OakLogTop.json",
|
||||
"OakLogTop.json",
|
||||
"OakLog.json",
|
||||
"OakLog.json"
|
||||
]
|
||||
}
|
||||
10
assets/blocks/OakLogZ.json
Normal file
10
assets/blocks/OakLogZ.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"materials": [
|
||||
"OakLog.json",
|
||||
"OakLog.json",
|
||||
"OakLog.json",
|
||||
"OakLog.json",
|
||||
"OakLogTop.json",
|
||||
"OakLogTop.json"
|
||||
]
|
||||
}
|
||||
3
assets/blocks/OakPlanks.json
Normal file
3
assets/blocks/OakPlanks.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "OakPlanks.json"
|
||||
}
|
||||
3
assets/blocks/Sand.json
Normal file
3
assets/blocks/Sand.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Sand.json"
|
||||
}
|
||||
3
assets/blocks/SmoothStone.json
Normal file
3
assets/blocks/SmoothStone.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "SmoothStone.json"
|
||||
}
|
||||
3
assets/blocks/Stone.json
Normal file
3
assets/blocks/Stone.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "Stone.json"
|
||||
}
|
||||
3
assets/blocks/StoneBricks.json
Normal file
3
assets/blocks/StoneBricks.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"material": "StoneBricks.json"
|
||||
}
|
||||
159
src/Game.zig
159
src/Game.zig
@@ -6,6 +6,8 @@ const vk = @import("vulkan");
|
||||
|
||||
const math = @import("math.zig");
|
||||
|
||||
const Blocks = @import("assets/Blocks.zig");
|
||||
const Chunk = @import("assets/Chunk.zig");
|
||||
const Materials = @import("assets/Materials.zig");
|
||||
const Textures = @import("assets/Textures.zig");
|
||||
const CommandBuffer = @import("engine/CommandBuffer.zig").CommandBuffer;
|
||||
@@ -58,7 +60,7 @@ const GlobalUniforms = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
const ObjectUniforms = extern struct {
|
||||
pub const ObjectUniforms = extern struct {
|
||||
matrixOStoWS: [16]f32,
|
||||
matrixOStoWSNormal: [16]f32,
|
||||
|
||||
@@ -106,8 +108,7 @@ swapchain: *Swapchain,
|
||||
global_descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
per_batch_descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
descriptor_pool: vk.DescriptorPool,
|
||||
/// [0] GLOBAL, [1] PER BATCH
|
||||
descriptor_sets: [2]vk.DescriptorSet,
|
||||
global_descriptor_set: vk.DescriptorSet,
|
||||
pipeline_layout: vk.PipelineLayout,
|
||||
pipeline: vk.Pipeline,
|
||||
|
||||
@@ -120,12 +121,12 @@ global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent),
|
||||
global_uniforms_transfer_semaphores: []vk.Semaphore,
|
||||
point_lights: PointLightBuffer,
|
||||
directional_lights: DirectionalLightBuffer,
|
||||
object_uniforms: ObjectUniformsBuffer,
|
||||
sampler: vk.Sampler,
|
||||
object_count: u32,
|
||||
|
||||
blocks: Blocks,
|
||||
materials: Materials,
|
||||
textures: Textures,
|
||||
chunks: std.ArrayList(Chunk),
|
||||
|
||||
camera_position: Vector3 = .init(0, 0, 1.62),
|
||||
camera_pitch: f32 = 0,
|
||||
@@ -144,7 +145,7 @@ const max_directional_lights = 4;
|
||||
const max_objects = 1024;
|
||||
|
||||
const camera_near_plane = 0.1;
|
||||
const camera_vertical_fov_deg = 90.0;
|
||||
const camera_vertical_fov_deg = 80.0;
|
||||
const camera_half_vertical_fov_rad = 0.5 * camera_vertical_fov_deg * std.math.rad_per_deg;
|
||||
const camera_mouse_sensitivity = 0.002;
|
||||
|
||||
@@ -158,7 +159,10 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
var textures = try Textures.init(engine, allocator);
|
||||
errdefer textures.deinit(engine, allocator);
|
||||
|
||||
materials.loadAll(engine, &textures, allocator);
|
||||
var blocks = try Blocks.init(allocator);
|
||||
errdefer blocks.deinit(allocator);
|
||||
|
||||
blocks.loadAll(engine, &materials, &textures, allocator);
|
||||
|
||||
const sampler = try engine.createSampler(.{
|
||||
.mag_filter = .linear,
|
||||
@@ -359,13 +363,6 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
});
|
||||
errdefer directional_lights.deinit(engine);
|
||||
|
||||
var object_uniforms = try ObjectUniformsBuffer.init(engine, .{
|
||||
.usage = .storage,
|
||||
.target_queue = .graphics,
|
||||
.array_capacity = max_objects,
|
||||
});
|
||||
errdefer object_uniforms.deinit(engine);
|
||||
|
||||
const pipeline = try engine.createGraphicsPipeline(.{
|
||||
.stages = &.{
|
||||
.{
|
||||
@@ -484,7 +481,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
errdefer engine.destroyPipeline(pipeline);
|
||||
|
||||
const descriptor_pool = try engine.createDescriptorPool(.{
|
||||
.max_sets = 2,
|
||||
.max_sets = 1 + 256,
|
||||
.pool_sizes = &.{
|
||||
.{
|
||||
.type = .sampler,
|
||||
@@ -500,19 +497,17 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
.{
|
||||
.type = .storage_buffer,
|
||||
.descriptor_count = 4,
|
||||
.descriptor_count = 3 + 256,
|
||||
},
|
||||
},
|
||||
});
|
||||
errdefer engine.destroyDescriptorPool(descriptor_pool);
|
||||
|
||||
// [0] GLOBAL, [1] PER BATCH
|
||||
var descriptor_sets: [2]vk.DescriptorSet = undefined;
|
||||
try engine.allocateDescriptorSets(.{
|
||||
const global_descriptor_set = try engine.allocateDescriptorSet(.{
|
||||
.descriptor_pool = descriptor_pool,
|
||||
.set_layouts = &.{ global_descriptor_set_layout, per_batch_descriptor_set_layout },
|
||||
.variable_descriptor_counts = &.{ @intCast(textures.textures.items.len), 0 },
|
||||
}, &descriptor_sets);
|
||||
.set_layout = global_descriptor_set_layout,
|
||||
.variable_descriptor_count = @intCast(textures.textures.items.len),
|
||||
});
|
||||
|
||||
const descriptor_images = try allocator.alloc(vk.DescriptorImageInfo, textures.textures.items.len);
|
||||
for (textures.textures.items, descriptor_images) |texture, *info| {
|
||||
@@ -527,7 +522,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
try engine.updateDescriptorSets(.{
|
||||
.writes = &.{
|
||||
.{
|
||||
.dst_set = descriptor_sets[0],
|
||||
.dst_set = global_descriptor_set,
|
||||
.dst_binding = 0,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .uniform_buffer,
|
||||
@@ -542,7 +537,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
},
|
||||
.{
|
||||
.dst_set = descriptor_sets[0],
|
||||
.dst_set = global_descriptor_set,
|
||||
.dst_binding = 1,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .storage_buffer,
|
||||
@@ -557,7 +552,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
},
|
||||
.{
|
||||
.dst_set = descriptor_sets[0],
|
||||
.dst_set = global_descriptor_set,
|
||||
.dst_binding = 2,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .storage_buffer,
|
||||
@@ -572,7 +567,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
},
|
||||
.{
|
||||
.dst_set = descriptor_sets[0],
|
||||
.dst_set = global_descriptor_set,
|
||||
.dst_binding = 3,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .storage_buffer,
|
||||
@@ -587,52 +582,45 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
},
|
||||
.{
|
||||
.dst_set = descriptor_sets[0],
|
||||
.dst_set = global_descriptor_set,
|
||||
.dst_binding = 5,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .sampled_image,
|
||||
.descriptor_infos = .{ .image = descriptor_images },
|
||||
},
|
||||
.{
|
||||
.dst_set = descriptor_sets[1],
|
||||
.dst_binding = 0,
|
||||
.dst_array_element = 0,
|
||||
.descriptor_type = .storage_buffer,
|
||||
.descriptor_infos = .{
|
||||
.buffer = &.{
|
||||
.{
|
||||
.buffer = object_uniforms.buffer,
|
||||
.offset = 0,
|
||||
.range = vk.WHOLE_SIZE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const point_lights_data: []const PointLight = &.{
|
||||
.{
|
||||
.positionWS = .{ 0, 0, 0.5 },
|
||||
.color = .{ 1, 1, 1 },
|
||||
},
|
||||
.{
|
||||
.positionWS = .{ -5, 5, 0.5 },
|
||||
.color = .{ 1, 0, 0 },
|
||||
},
|
||||
.{
|
||||
.positionWS = .{ 5, 5, 0.5 },
|
||||
.color = .{ 0, 0, 1 },
|
||||
},
|
||||
.{
|
||||
.positionWS = .{ -5, -5, 0.5 },
|
||||
.color = .{ 0, 1, 0 },
|
||||
},
|
||||
.{
|
||||
.positionWS = .{ 5, -5, 0.5 },
|
||||
.color = .{ 1, 1, 0 },
|
||||
},
|
||||
};
|
||||
var chunks: std.ArrayList(Chunk) = .empty;
|
||||
errdefer {
|
||||
for (chunks.items) |*chunk| {
|
||||
chunk.deinit(engine, descriptor_pool);
|
||||
}
|
||||
chunks.deinit(allocator);
|
||||
}
|
||||
|
||||
var it: Iterator3 = .init(.init(-64, -64, 0), .init(64, 64, 0), .init(16, 16, 16));
|
||||
while (it.next()) |origin| {
|
||||
try chunks.ensureUnusedCapacity(allocator, 1);
|
||||
chunks.appendAssumeCapacity(try Chunk.init(engine, .{
|
||||
.origin = origin,
|
||||
.descriptor_pool = descriptor_pool,
|
||||
.per_batch_descriptor_set_layout = per_batch_descriptor_set_layout,
|
||||
}));
|
||||
|
||||
const chunk = &chunks.items[chunks.items.len - 1];
|
||||
|
||||
var it2 = Iterator3.init(.init(0, 0, 0), .init(1, 1, 0), .{ .vector = @splat(1.0 / 16.0) });
|
||||
while (it2.next()) |fpos| {
|
||||
const x, const y, const z = fpos.asArrayNorm(u4);
|
||||
const block: Blocks.Id = @enumFromInt(engine.random.intRangeLessThan(u12, 1, @intCast(blocks.blocks.items.len)));
|
||||
chunk.blocks[z][y][x] = block;
|
||||
}
|
||||
|
||||
try chunk.refresh(engine, &blocks, allocator);
|
||||
}
|
||||
|
||||
const point_lights_data: []const PointLight = &.{};
|
||||
try point_lights.write(engine, .{
|
||||
.header = @intCast(point_lights_data.len),
|
||||
.elements = point_lights_data,
|
||||
@@ -649,26 +637,6 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
.elements = directional_lights_data,
|
||||
});
|
||||
|
||||
const object_count: u32 = blk: {
|
||||
var objects: std.ArrayList(ObjectUniforms) = try .initCapacity(allocator, 578);
|
||||
defer objects.deinit(allocator);
|
||||
|
||||
var it = Iterator3.init(.init(-8, -8, 0), .init(8, 8, 2), .init(1, 1, 2));
|
||||
while (it.next()) |pos| {
|
||||
const material: Materials.Id = @enumFromInt(engine.random.uintLessThan(u16, @intFromEnum(materials.next_id)));
|
||||
const matrix_os_to_ws = Matrix4x4.initTranslation(pos);
|
||||
const matrix_os_to_ws_normal = Matrix4x4.inverseTransposeAffine(matrix_os_to_ws);
|
||||
objects.appendAssumeCapacity(.{
|
||||
.matrixOStoWS = matrix_os_to_ws.asArray(),
|
||||
.matrixOStoWSNormal = matrix_os_to_ws_normal.asArray(),
|
||||
.material = material,
|
||||
});
|
||||
}
|
||||
try object_uniforms.write(engine, .{ .elements = objects.items });
|
||||
|
||||
break :blk @intCast(objects.items.len);
|
||||
};
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.engine = engine,
|
||||
@@ -676,7 +644,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
.global_descriptor_set_layout = global_descriptor_set_layout,
|
||||
.per_batch_descriptor_set_layout = per_batch_descriptor_set_layout,
|
||||
.descriptor_pool = descriptor_pool,
|
||||
.descriptor_sets = descriptor_sets,
|
||||
.global_descriptor_set = global_descriptor_set,
|
||||
.pipeline_layout = pipeline_layout,
|
||||
.pipeline = pipeline,
|
||||
|
||||
@@ -689,12 +657,12 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
.global_uniforms_transfer_semaphores = global_uniforms_transfer_semaphores,
|
||||
.point_lights = point_lights,
|
||||
.directional_lights = directional_lights,
|
||||
.object_uniforms = object_uniforms,
|
||||
.sampler = sampler,
|
||||
.object_count = object_count,
|
||||
|
||||
.blocks = blocks,
|
||||
.materials = materials,
|
||||
.textures = textures,
|
||||
.chunks = chunks,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -703,13 +671,16 @@ pub fn deinit(self: *Game) void {
|
||||
|
||||
self.vertex_buffer.deinit(self.engine);
|
||||
self.index_buffer.deinit(self.engine);
|
||||
for (self.chunks.items) |*chunk| {
|
||||
chunk.deinit(self.engine, self.descriptor_pool);
|
||||
}
|
||||
self.chunks.deinit(self.allocator);
|
||||
|
||||
self.global_uniforms.deinit(self.engine);
|
||||
self.global_uniforms_staging_buffer.deinit(self.engine);
|
||||
self.global_uniforms_transfer_command_buffer.deinit(self.engine);
|
||||
self.point_lights.deinit(self.engine);
|
||||
self.directional_lights.deinit(self.engine);
|
||||
self.object_uniforms.deinit(self.engine);
|
||||
|
||||
for (self.global_uniforms_transfer_semaphores) |semaphore| {
|
||||
self.engine.destroySemaphore(semaphore);
|
||||
@@ -725,6 +696,7 @@ pub fn deinit(self: *Game) void {
|
||||
|
||||
self.textures.deinit(self.engine, self.allocator);
|
||||
self.materials.deinit(self.engine, self.allocator);
|
||||
self.blocks.deinit(self.allocator);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
@@ -768,7 +740,7 @@ pub fn update(self: *Game, dt: f32) void {
|
||||
);
|
||||
// zig fmt: on
|
||||
|
||||
const ambient_light = Vector3.init(0.2, 0.2, 0.2);
|
||||
const ambient_light = Vector3.init(0.001, 0.001, 0.001);
|
||||
|
||||
const global_uniforms_data: GlobalUniforms = .{
|
||||
.matrixWStoVS = matrix_ws_to_vs.asArray(),
|
||||
@@ -926,12 +898,11 @@ fn render(self: *Game) !void {
|
||||
},
|
||||
});
|
||||
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
||||
command_buffer.bindDescriptorSets(.graphics, self.pipeline_layout, 0, &self.descriptor_sets, &.{});
|
||||
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.global_descriptor_set, null);
|
||||
|
||||
command_buffer.drawIndexed(.{
|
||||
.index_count = self.index_buffer.array_capacity,
|
||||
.instance_count = self.object_count,
|
||||
});
|
||||
for (self.chunks.items) |chunk| {
|
||||
chunk.draw(self.pipeline_layout, command_buffer);
|
||||
}
|
||||
}
|
||||
try command_buffer.endCommandBuffer();
|
||||
|
||||
|
||||
262
src/assets/Blocks.zig
Normal file
262
src/assets/Blocks.zig
Normal file
@@ -0,0 +1,262 @@
|
||||
const Blocks = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const atoms = @import("../engine/atoms.zig");
|
||||
const Engine = @import("../engine/Engine.zig");
|
||||
const Materials = @import("Materials.zig");
|
||||
const Textures = @import("Textures.zig");
|
||||
|
||||
pub const Block = struct {
|
||||
positive_x: Materials.Id,
|
||||
negative_x: Materials.Id,
|
||||
positive_y: Materials.Id,
|
||||
negative_y: Materials.Id,
|
||||
positive_z: Materials.Id,
|
||||
negative_z: Materials.Id,
|
||||
|
||||
pub fn initUniform(material: Materials.Id) Block {
|
||||
return .{
|
||||
.positive_x = material,
|
||||
.negative_x = material,
|
||||
.positive_y = material,
|
||||
.negative_y = material,
|
||||
.positive_z = material,
|
||||
.negative_z = material,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn initSeparate(
|
||||
positive_x: Materials.Id,
|
||||
negative_x: Materials.Id,
|
||||
positive_y: Materials.Id,
|
||||
negative_y: Materials.Id,
|
||||
positive_z: Materials.Id,
|
||||
negative_z: Materials.Id,
|
||||
) Block {
|
||||
return .{
|
||||
.positive_x = positive_x,
|
||||
.negative_x = negative_x,
|
||||
.positive_y = positive_y,
|
||||
.negative_y = negative_y,
|
||||
.positive_z = positive_z,
|
||||
.negative_z = negative_z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn initArray(materials: [6]Materials.Id) Block {
|
||||
return .{
|
||||
.positive_x = materials[0],
|
||||
.negative_x = materials[1],
|
||||
.positive_y = materials[2],
|
||||
.negative_y = materials[3],
|
||||
.positive_z = materials[4],
|
||||
.negative_z = materials[5],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
map: Map,
|
||||
blocks: Array,
|
||||
|
||||
pub const capacity = std.math.maxInt(std.meta.Tag(Id));
|
||||
|
||||
pub const Key = struct { atom: atoms.Atom };
|
||||
pub const Id = enum(u12) {
|
||||
air = 0,
|
||||
_,
|
||||
|
||||
pub fn next(self: Id) Id {
|
||||
return @enumFromInt(@intFromEnum(self) + 1);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Map = std.AutoHashMapUnmanaged(Key, Id);
|
||||
pub const Array = std.ArrayList(Block);
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) !Blocks {
|
||||
var map: Map = .empty;
|
||||
errdefer map.deinit(allocator);
|
||||
try map.ensureTotalCapacity(allocator, capacity);
|
||||
|
||||
var blocks: Array = try .initCapacity(allocator, capacity);
|
||||
errdefer blocks.deinit(allocator);
|
||||
|
||||
const air = Block.initUniform(.empty);
|
||||
blocks.appendAssumeCapacity(air);
|
||||
|
||||
return .{
|
||||
.map = map,
|
||||
.blocks = blocks,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Blocks, allocator: std.mem.Allocator) void {
|
||||
std.log.debug("Deinitializing {*} with Allocator{{{*},{*}}}", .{ self, allocator.ptr, allocator.vtable });
|
||||
|
||||
self.blocks.deinit(allocator);
|
||||
self.map.deinit(allocator);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn getAtom(self: *const Blocks, atom: atoms.Atom) ?Id {
|
||||
const key: Key = .{ .atom = atom };
|
||||
return self.map.get(key);
|
||||
}
|
||||
|
||||
pub fn getFilename(self: *const Blocks, filename: []const u8) ?Id {
|
||||
const atom = atoms.getAtom(filename) orelse return null;
|
||||
const key: Key = .{ .atom = atom };
|
||||
return self.map.get(key);
|
||||
}
|
||||
|
||||
pub fn getBlock(self: *const Blocks, id: Id) ?*Block {
|
||||
const index: usize = @intFromEnum(id);
|
||||
return if (index < self.blocks.items.len) &self.blocks.items[index] else null;
|
||||
}
|
||||
|
||||
pub fn getOrLoadAtom(
|
||||
self: *Blocks,
|
||||
engine: *Engine,
|
||||
materials: *Materials,
|
||||
textures: *Textures,
|
||||
atom: atoms.Atom,
|
||||
temp_allocator: std.mem.Allocator,
|
||||
) !Id {
|
||||
const key: Key = .{ .atom = atom };
|
||||
const entry = self.map.getOrPutAssumeCapacity(key);
|
||||
|
||||
if (entry.found_existing) {
|
||||
return entry.value_ptr.*;
|
||||
} else {
|
||||
errdefer _ = self.map.remove(key);
|
||||
const block = try loadBlock(engine, materials, textures, atoms.getString(atom), temp_allocator);
|
||||
const id = self.nextId();
|
||||
entry.value_ptr.* = id;
|
||||
self.blocks.appendAssumeCapacity(block);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOrLoadFilename(
|
||||
self: *Blocks,
|
||||
engine: *Engine,
|
||||
materials: *Materials,
|
||||
textures: *Textures,
|
||||
filename: []const u8,
|
||||
temp_allocator: std.mem.Allocator,
|
||||
) !Id {
|
||||
const atom = try atoms.getOrPutAtom(filename);
|
||||
const key: Key = .{ .atom = atom };
|
||||
const entry = self.map.getOrPutAssumeCapacity(key);
|
||||
|
||||
if (entry.found_existing) {
|
||||
return entry.value_ptr.*;
|
||||
} else {
|
||||
errdefer _ = self.map.remove(key);
|
||||
const texture = try loadBlock(engine, materials, textures, filename, temp_allocator);
|
||||
const id = self.nextId();
|
||||
entry.value_ptr.* = id;
|
||||
self.blocks.appendAssumeCapacity(texture);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loadAll(
|
||||
self: *Blocks,
|
||||
engine: *Engine,
|
||||
materials: *Materials,
|
||||
textures: *Textures,
|
||||
temp_allocator: std.mem.Allocator,
|
||||
) void {
|
||||
const cwd = std.fs.cwd();
|
||||
|
||||
var dir = cwd.openDir("assets/blocks", .{ .iterate = true }) catch |err| {
|
||||
std.log.err("Error while opening blocks directory: {s}", .{@errorName(err)});
|
||||
return;
|
||||
};
|
||||
defer dir.close();
|
||||
|
||||
var it = dir.iterate();
|
||||
while (it.next() catch |err| {
|
||||
std.log.err("Error while iterating over blocks directory: {s}", .{@errorName(err)});
|
||||
return;
|
||||
}) |entry| {
|
||||
if (entry.kind != .file) {
|
||||
std.log.warn("Skipping block entry {s}, which is not a file", .{entry.name});
|
||||
continue;
|
||||
}
|
||||
|
||||
_ = self.getOrLoadFilename(engine, materials, textures, entry.name, temp_allocator) catch |err| {
|
||||
std.log.err("Error while loading block entry {s}: {s}", .{ entry.name, @errorName(err) });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn loadBlock(
|
||||
engine: *Engine,
|
||||
materials: *Materials,
|
||||
textures: *Textures,
|
||||
filename: []const u8,
|
||||
temp_allocator: std.mem.Allocator,
|
||||
) !Block {
|
||||
const BlockJson = struct {
|
||||
material: ?[]const u8 = null,
|
||||
materials: ?[6][]const u8 = null,
|
||||
};
|
||||
|
||||
std.log.debug("Loading block \"{s}\"...", .{filename});
|
||||
|
||||
const cwd = std.fs.cwd();
|
||||
|
||||
var dir = try cwd.openDir("assets/blocks", .{});
|
||||
defer dir.close();
|
||||
|
||||
// NOTE Buffer size approximated based on expected JSON structure.
|
||||
var buffer: [256]u8 = undefined;
|
||||
|
||||
const file = try dir.openFile(filename, .{});
|
||||
defer file.close();
|
||||
|
||||
var file_reader = file.reader(&buffer);
|
||||
var json_reader: std.json.Reader = .init(temp_allocator, &file_reader.interface);
|
||||
defer json_reader.deinit();
|
||||
|
||||
const parsed: std.json.Parsed(BlockJson) = try std.json.parseFromTokenSource(BlockJson, temp_allocator, &json_reader, .{
|
||||
.duplicate_field_behavior = .@"error",
|
||||
.ignore_unknown_fields = false,
|
||||
.allocate = .alloc_if_needed,
|
||||
});
|
||||
defer parsed.deinit();
|
||||
|
||||
const block_json = parsed.value;
|
||||
|
||||
const block: Block = blk: {
|
||||
if (block_json.material) |name| {
|
||||
if (block_json.materials != null) {
|
||||
std.log.err("Block entry {s} has both properties \"material\" and \"materials\" defined, but exactly one of them must be defined", .{filename});
|
||||
return error.ParseError;
|
||||
}
|
||||
|
||||
const material = try materials.getOrLoadFilename(engine, textures, name, temp_allocator);
|
||||
break :blk .initUniform(material);
|
||||
}
|
||||
|
||||
if (block_json.materials) |names| {
|
||||
var ids: [6]Materials.Id = undefined;
|
||||
for (names, &ids) |name, *id| {
|
||||
id.* = try materials.getOrLoadFilename(engine, textures, name, temp_allocator);
|
||||
}
|
||||
break :blk .initArray(ids);
|
||||
}
|
||||
|
||||
std.log.err("Block entry {s} has neither \"material\" or \"materials\" properties defined, but exactly one of them must be defined", .{filename});
|
||||
return error.ParseError;
|
||||
};
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
fn nextId(self: *const Blocks) Id {
|
||||
const index = self.blocks.items.len;
|
||||
return @enumFromInt(index);
|
||||
}
|
||||
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 });
|
||||
}
|
||||
@@ -19,6 +19,7 @@ pub const capacity = std.math.maxInt(std.meta.Tag(Id));
|
||||
|
||||
pub const Key = struct { atom: atoms.Atom };
|
||||
pub const Id = enum(u16) {
|
||||
empty,
|
||||
_,
|
||||
|
||||
pub fn next(self: Id) Id {
|
||||
@@ -55,10 +56,12 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Materials {
|
||||
});
|
||||
errdefer material_buffer.deinit(engine);
|
||||
|
||||
// TODO Add "error" material to represent the empty value (it shouldn't be rendered, so it's good to know when it is).
|
||||
|
||||
return .{
|
||||
.map = map,
|
||||
.material_buffer = material_buffer,
|
||||
.next_id = @enumFromInt(0),
|
||||
.next_id = @enumFromInt(1),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,12 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
|
||||
errdefer map.deinit(allocator);
|
||||
try map.ensureTotalCapacity(allocator, capacity);
|
||||
|
||||
var array: Array = try .initCapacity(allocator, capacity);
|
||||
var textures: Array = try .initCapacity(allocator, capacity);
|
||||
errdefer {
|
||||
for (array.items) |*texture| {
|
||||
for (textures.items) |*texture| {
|
||||
texture.deinit(engine);
|
||||
}
|
||||
array.deinit(allocator);
|
||||
textures.deinit(allocator);
|
||||
}
|
||||
|
||||
const empty_base_color_texture = try Texture.init(engine, .{
|
||||
@@ -51,6 +51,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
|
||||
.usage = .base_color,
|
||||
.target_queue = .graphics,
|
||||
});
|
||||
textures.appendAssumeCapacity(empty_base_color_texture);
|
||||
|
||||
const empty_emissive_texture = try Texture.init(engine, .{
|
||||
.width = 1,
|
||||
@@ -58,6 +59,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
|
||||
.usage = .emissive,
|
||||
.target_queue = .graphics,
|
||||
});
|
||||
textures.appendAssumeCapacity(empty_emissive_texture);
|
||||
|
||||
const empty_normal_texture = try Texture.init(engine, .{
|
||||
.width = 1,
|
||||
@@ -65,6 +67,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
|
||||
.usage = .normal,
|
||||
.target_queue = .graphics,
|
||||
});
|
||||
textures.appendAssumeCapacity(empty_normal_texture);
|
||||
|
||||
const empty_occlusuion_roughness_metallic_texture = try Texture.init(engine, .{
|
||||
.width = 1,
|
||||
@@ -72,13 +75,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
|
||||
.usage = .occlusion_roughness_metallic,
|
||||
.target_queue = .graphics,
|
||||
});
|
||||
|
||||
array.appendSliceAssumeCapacity(&.{
|
||||
empty_base_color_texture,
|
||||
empty_emissive_texture,
|
||||
empty_normal_texture,
|
||||
empty_occlusuion_roughness_metallic_texture,
|
||||
});
|
||||
textures.appendAssumeCapacity(empty_occlusuion_roughness_metallic_texture);
|
||||
|
||||
try empty_base_color_texture.writeSamples(u8, engine, &.{ 255, 255, 255, 255 });
|
||||
try empty_emissive_texture.writeSamples(f16, engine, &.{ 1.0, 1.0, 1.0, 1.0 });
|
||||
@@ -87,7 +84,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
|
||||
|
||||
return .{
|
||||
.map = map,
|
||||
.textures = array,
|
||||
.textures = textures,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -114,14 +111,10 @@ pub fn getFilename(self: *const Textures, filename: []const u8, usage: Texture.U
|
||||
}
|
||||
|
||||
pub fn getTexture(self: *const Textures, id: Id) ?*Texture {
|
||||
const index: usize = id.id;
|
||||
const index: usize = @intFromEnum(id);
|
||||
return if (index < self.textures.items.len) &self.textures.items[index] else null;
|
||||
}
|
||||
|
||||
pub fn getId(self: *const Textures, key: Key) ?Id {
|
||||
return self.map.get(key);
|
||||
}
|
||||
|
||||
pub fn getOrLoadAtom(self: *Textures, engine: *Engine, atom: atoms.Atom, usage: Texture.Usage, temp_allocator: std.mem.Allocator) !Id {
|
||||
const key: Key = .{ .atom = atom, .usage = usage };
|
||||
const entry = self.map.getOrPutAssumeCapacity(key);
|
||||
@@ -130,7 +123,7 @@ pub fn getOrLoadAtom(self: *Textures, engine: *Engine, atom: atoms.Atom, usage:
|
||||
return entry.value_ptr.*;
|
||||
} else {
|
||||
errdefer _ = self.map.remove(key);
|
||||
const texture = try self.loadTexture(engine, atoms.getString(atom), usage, temp_allocator);
|
||||
const texture = try loadTexture(engine, atoms.getString(atom), usage, temp_allocator);
|
||||
const id = self.nextId();
|
||||
entry.value_ptr.* = id;
|
||||
self.textures.appendAssumeCapacity(texture);
|
||||
|
||||
@@ -92,6 +92,23 @@ pub fn CommandBuffer(comptime queue_type: QueueType, comptime transient: Transie
|
||||
}, contents);
|
||||
}
|
||||
|
||||
pub inline fn bindDescriptorSet(
|
||||
self: Self,
|
||||
pipeline_bind_point: vk.PipelineBindPoint,
|
||||
layout: vk.PipelineLayout,
|
||||
set: u32,
|
||||
descriptor_set: vk.DescriptorSet,
|
||||
dynamic_offset: ?u32,
|
||||
) void {
|
||||
self.bindDescriptorSets(
|
||||
pipeline_bind_point,
|
||||
layout,
|
||||
set,
|
||||
&.{descriptor_set},
|
||||
if (dynamic_offset) |x| &.{x} else &.{},
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn bindDescriptorSets(
|
||||
self: Self,
|
||||
pipeline_bind_point: vk.PipelineBindPoint,
|
||||
|
||||
@@ -570,6 +570,12 @@ pub const DescriptorPoolCreateInfo = struct {
|
||||
};
|
||||
|
||||
pub const DescriptorSetAllocateInfo = struct {
|
||||
descriptor_pool: vk.DescriptorPool,
|
||||
set_layout: vk.DescriptorSetLayout,
|
||||
variable_descriptor_count: ?u32 = null,
|
||||
};
|
||||
|
||||
pub const DescriptorSetsAllocateInfo = struct {
|
||||
descriptor_pool: vk.DescriptorPool,
|
||||
set_layouts: []const vk.DescriptorSetLayout,
|
||||
variable_descriptor_counts: []const u32 = &.{},
|
||||
@@ -733,7 +739,17 @@ pub fn createBuffer(self: *Engine, create_info: BufferCreateInfo) !vk.Buffer {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
pub fn allocateDescriptorSets(self: *Engine, allocate_info: DescriptorSetAllocateInfo, descriptor_sets: []vk.DescriptorSet) !void {
|
||||
pub fn allocateDescriptorSet(self: *Engine, allocate_info: DescriptorSetAllocateInfo) !vk.DescriptorSet {
|
||||
var descriptor_sets: [1]vk.DescriptorSet = undefined;
|
||||
try self.allocateDescriptorSets(.{
|
||||
.descriptor_pool = allocate_info.descriptor_pool,
|
||||
.set_layouts = &.{allocate_info.set_layout},
|
||||
.variable_descriptor_counts = if (allocate_info.variable_descriptor_count) |x| &.{x} else &.{},
|
||||
}, &descriptor_sets);
|
||||
return descriptor_sets[0];
|
||||
}
|
||||
|
||||
pub fn allocateDescriptorSets(self: *Engine, allocate_info: DescriptorSetsAllocateInfo, descriptor_sets: []vk.DescriptorSet) !void {
|
||||
std.debug.assert(descriptor_sets.len >= allocate_info.set_layouts.len);
|
||||
|
||||
const has_variable_descriptor_counts = allocate_info.variable_descriptor_counts.len > 0;
|
||||
@@ -1031,6 +1047,11 @@ pub fn destroyShaderModule(self: *Engine, shader_module: vk.ShaderModule) void {
|
||||
self.device.destroyShaderModule(shader_module, &self.vk_allocator.interface);
|
||||
}
|
||||
|
||||
pub fn freeDescriptorSet(self: *Engine, descriptor_pool: vk.DescriptorPool, descriptor_set: vk.DescriptorSet) void {
|
||||
const descriptor_sets = [_]vk.DescriptorSet{descriptor_set};
|
||||
self.device.freeDescriptorSets(descriptor_pool, descriptor_sets.len, &descriptor_sets) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn freeMemory(self: *Engine, device_memory: vk.DeviceMemory) void {
|
||||
self.device.freeMemory(device_memory, &self.vk_allocator.interface);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user