Make use of some globals to stop typing engine everywhere.

This commit is contained in:
2026-05-15 02:20:08 +02:00
parent 36434f8107
commit ad80fb4fd9
21 changed files with 902 additions and 798 deletions

View File

@@ -3,6 +3,7 @@
const Blocks = @This();
const std = @import("std");
const ctx = @import("../AppContext.zig");
const media = @import("media");
const voxels = @import("../voxels.zig");
@@ -76,23 +77,26 @@ pub const Definition = struct {
}
};
/// Maps a key value to a block definition ID.
/// Maps a key value to a block definition ID. Preallocated with
/// `allocator_general`.
map: std.AutoHashMapUnmanaged(Key, Id),
/// Stores all `Definition` structs and maps a block definition ID to a
/// `Definition` struct.
/// `Definition` struct. Preallocated with `allocator_general`.
array: std.ArrayList(Definition),
/// With `@sizeOf(Definition) == 24` and `max_blocks = 4096`, the block
/// definitions should take ~95.4 kiB in RAM.
pub const max_blocks = 4096;
pub fn init(allocator: std.mem.Allocator) !Blocks {
var map: std.AutoHashMapUnmanaged(Key, Id) = .empty;
errdefer map.deinit(allocator);
try map.ensureTotalCapacity(allocator, max_blocks);
pub fn init() !Blocks {
const allocator_general = ctx.allocator_general;
var array: std.ArrayList(Definition) = try .initCapacity(allocator, max_blocks);
errdefer array.deinit(allocator);
var map: std.AutoHashMapUnmanaged(Key, Id) = .empty;
errdefer map.deinit(allocator_general);
try map.ensureTotalCapacity(allocator_general, max_blocks);
var array: std.ArrayList(Definition) = try .initCapacity(allocator_general, max_blocks);
errdefer array.deinit(allocator_general);
// VOLATILE Synchronize with explicit values on top of `Id` type.
@@ -104,11 +108,13 @@ pub fn init(allocator: std.mem.Allocator) !Blocks {
};
}
pub fn deinit(self: *Blocks, allocator: std.mem.Allocator) void {
std.log.scoped(.deinit).debug("Deinitializing {*} with Allocator{{{*},{*}}}", .{ self, allocator.ptr, allocator.vtable });
pub fn deinit(self: *Blocks) void {
const allocator_general = ctx.allocator_general;
self.array.deinit(allocator);
self.map.deinit(allocator);
std.log.scoped(.deinit).debug("Deinitializing {*}", .{self});
self.array.deinit(allocator_general);
self.map.deinit(allocator_general);
self.* = undefined;
}
@@ -132,18 +138,15 @@ pub fn getAtom(self: *const Blocks, filename: Atom) ?Id {
pub fn getOrLoad(
self: *Blocks,
engine: *Engine,
materials: *Materials,
textures: *Textures,
stbi: *media.stbi,
filename: []const u8,
temp_allocator: std.mem.Allocator,
io: std.Io,
) !Id {
const key: Key = .{
// If the material already exists, then the atom must exist and the
// following line will not return any error.
.filename = try .fromString(filename, io),
.filename = try .fromString(filename),
};
// We don't use `getOrPutAssumeCapacity` method, because we might already be
@@ -155,7 +158,7 @@ pub fn getOrLoad(
const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) {
error.Overflow => return error.OutOfBlocks,
};
const def = try loadBlock(engine, materials, textures, stbi, filename, temp_allocator, io);
const def = try loadBlock(materials, textures, stbi, filename);
self.map.putAssumeCapacityNoClobber(key, id);
self.array.appendAssumeCapacity(def);
@@ -166,13 +169,10 @@ pub fn getOrLoad(
pub fn getOrLoadAtom(
self: *Blocks,
engine: *Engine,
materials: *Materials,
textures: *Textures,
stbi: *media.stbi,
filename: Atom,
temp_allocator: std.mem.Allocator,
io: std.Io,
) !Id {
const key: Key = .{
.filename = filename,
@@ -187,7 +187,7 @@ pub fn getOrLoadAtom(
const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) {
error.Overflow => return error.OutOfBlocks,
};
const def = try loadBlock(engine, materials, textures, stbi, filename.toString(), temp_allocator, io);
const def = try loadBlock(materials, textures, stbi, filename.toString());
self.map.putAssumeCapacityNoClobber(key, id);
self.array.appendAssumeCapacity(def);
@@ -198,13 +198,12 @@ pub fn getOrLoadAtom(
pub fn loadAll(
self: *Blocks,
engine: *Engine,
materials: *Materials,
textures: *Textures,
stbi: *media.stbi,
temp_allocator: std.mem.Allocator,
io: std.Io,
) void {
const io = ctx.io;
const cwd = std.Io.Dir.cwd();
var dir = cwd.openDir(io, "assets/blocks", .{ .iterate = true }) catch |err| {
@@ -223,21 +222,21 @@ pub fn loadAll(
continue;
}
_ = self.getOrLoad(engine, materials, textures, stbi, entry.name, temp_allocator, io) catch |err| {
_ = self.getOrLoad(materials, textures, stbi, entry.name) catch |err| {
std.log.err("Error while loading block definition entry {s}: {s}", .{ entry.name, @errorName(err) });
};
}
}
fn loadBlock(
engine: *Engine,
materials: *Materials,
textures: *Textures,
stbi: *media.stbi,
filename: []const u8,
temp_allocator: std.mem.Allocator,
io: std.Io,
) !Definition {
const allocator_frame = ctx.allocator_frame;
const io = ctx.io;
const DefinitionJson = struct {
pub const Wall = struct {
material: ?[]const u8 = null,
@@ -264,17 +263,13 @@ fn loadBlock(
defer file.close(io);
var file_reader = file.reader(io, &buffer);
var json_reader = std.json.Reader.init(temp_allocator, &file_reader.interface);
defer json_reader.deinit();
var json_reader = std.json.Reader.init(allocator_frame, &file_reader.interface);
const parsed: std.json.Parsed(DefinitionJson) = try std.json.parseFromTokenSource(DefinitionJson, temp_allocator, &json_reader, .{
const def_json = try std.json.parseFromTokenSourceLeaky(DefinitionJson, allocator_frame, &json_reader, .{
.duplicate_field_behavior = .@"error",
.ignore_unknown_fields = false,
.allocate = .alloc_if_needed,
});
defer parsed.deinit();
const def_json = parsed.value;
const block: Definition = blk: {
if (def_json.material) |name| {
@@ -283,7 +278,7 @@ fn loadBlock(
return error.ParseError;
}
const material = try materials.getOrLoad(engine, textures, stbi, name, temp_allocator, io);
const material = try materials.getOrLoad(textures, stbi, name);
break :blk .initUniform(material);
}
@@ -293,7 +288,7 @@ fn loadBlock(
var ret: Definition.Walls = undefined;
inline for (@typeInfo(voxels.Orientation).@"enum".fields) |field| {
@field(ret, field.name) = .{
.material = try materials.getOrLoad(engine, textures, stbi, @field(walls, field.name).material, temp_allocator, io),
.material = try materials.getOrLoad(textures, stbi, @field(walls, field.name).material),
.transform = @field(walls, field.name).transform,
};
}

View File

@@ -1,6 +1,7 @@
const Chunk = @This();
const std = @import("std");
const ctx = @import("../AppContext.zig");
const math = @import("../math.zig");
const shaders = @import("../shaders.zig");
const vk = @import("vulkan");
@@ -40,19 +41,21 @@ pub const InitInfo = struct {
pub const Neighbors = std.enums.EnumFieldStruct(voxels.Orientation, ?*const Chunk, null);
pub fn init(engine: *Engine, init_info: InitInfo) !Chunk {
pub fn init(init_info: InitInfo) !Chunk {
const engine = ctx.engine;
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, .{
var object_buffer: ObjectUniformsBuffer = try .init(.{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = initial_capacity,
});
errdefer object_buffer.deinit(engine);
errdefer object_buffer.deinit();
try engine.updateDescriptorSets(.{
.writes = &.{
@@ -89,18 +92,22 @@ pub fn init(engine: *Engine, init_info: InitInfo) !Chunk {
};
}
pub fn deinit(self: *Chunk, engine: *Engine, descriptor_pool: vk.DescriptorPool) void {
std.log.scoped(.deinit).debug("Deinitializing chunk {d} with {*} and {s}#{X}", .{ self.chunk_id, engine, @typeName(vk.DescriptorPool), @intFromEnum(descriptor_pool) });
pub fn deinit(self: *Chunk, descriptor_pool: vk.DescriptorPool) void {
const engine = ctx.engine;
self.object_buffer.deinit(engine);
std.log.scoped(.deinit).debug("Deinitializing chunk {d} with {s}#{X}", .{ self.chunk_id, @typeName(vk.DescriptorPool), @intFromEnum(descriptor_pool) });
self.object_buffer.deinit();
engine.freeDescriptorSet(descriptor_pool, self.descriptor_set);
self.* = undefined;
}
pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors: Neighbors, temp_allocator: std.mem.Allocator) !void {
var uniforms: std.ArrayList(shaders.ObjectUniforms) = try .initCapacity(temp_allocator, initial_capacity);
defer uniforms.deinit(temp_allocator);
pub fn refresh(self: *Chunk, blocks: *const Blocks, neighbors: Neighbors) !void {
const allocator_frame = ctx.allocator_frame;
const engine = ctx.engine;
var uniforms: std.ArrayList(shaders.ObjectUniforms) = try .initCapacity(allocator_frame, initial_capacity);
for (self.blocks, 0..) |plane, iz| {
const fz: f32 = @floatFromInt(iz);
@@ -116,7 +123,7 @@ pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors:
const material = @field(block.walls, field.name).material;
if (material != .empty and self.getOpposite(side, ix, iy, iz, blocks, neighbors) == .empty) {
const matrix = getMatrix(side, origin);
try uniforms.append(temp_allocator, .{
try uniforms.append(allocator_frame, .{
.matrixOStoWS = matrix,
.matrixOStoWSNormal = matrix,
.material = material,
@@ -130,7 +137,7 @@ pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors:
const object_count: u32 = @intCast(uniforms.items.len);
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, .{
const new_object_buffer: ObjectUniformsBuffer = try .init(.{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = desired_capacity,
@@ -156,13 +163,13 @@ pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors:
},
});
self.object_buffer.deinit(engine);
self.object_buffer.deinit();
self.object_buffer = new_object_buffer;
engine.setObjectName(new_object_buffer.buffer, "B Chunk[{d}]", .{self.chunk_id});
engine.setObjectName(new_object_buffer.device_memory, "DM Chunk[{d}]", .{self.chunk_id});
}
try self.object_buffer.write(engine, .{ .elements = uniforms.items });
try self.object_buffer.write(.{ .elements = uniforms.items });
self.object_count = object_count;
}

View File

@@ -3,6 +3,7 @@
const Materials = @This();
const std = @import("std");
const ctx = @import("../AppContext.zig");
const media = @import("media");
const shaders = @import("../shaders.zig");
const vk = @import("vulkan");
@@ -50,7 +51,7 @@ pub const Key = struct {
filename: Atom,
};
/// Maps a key value to a material ID.
/// Maps a key value to a material ID. Preallocated with `allocator_general`.
map: std.AutoHashMapUnmanaged(Key, Id),
/// Stores all material data in a single contiguous storage buffer. Use the
/// material ID as an index into this buffer.
@@ -62,22 +63,24 @@ material_count: usize,
/// storage buffer should take 208 kiB in VRAM.
pub const max_materials = 4096;
pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Materials {
var map: std.AutoHashMapUnmanaged(Key, Id) = .empty;
errdefer map.deinit(allocator);
try map.ensureTotalCapacity(allocator, max_materials);
pub fn init() !Materials {
const allocator_general = ctx.allocator_general;
var material_buffer = try shaders.MaterialBuffer.init(engine, .{
var map: std.AutoHashMapUnmanaged(Key, Id) = .empty;
errdefer map.deinit(allocator_general);
try map.ensureTotalCapacity(allocator_general, max_materials);
var material_buffer = try shaders.MaterialBuffer.init(.{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = max_materials,
.name = "Materials",
});
errdefer material_buffer.deinit(engine);
errdefer material_buffer.deinit();
// VOLATILE Synchronize with explicit values on top of `Id` type.
try material_buffer.write(engine, .{
try material_buffer.write(.{
.element_offset = Id.empty.toInt(),
.elements = &.{
.{
@@ -103,11 +106,13 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Materials {
};
}
pub fn deinit(self: *Materials, engine: *Engine, allocator: std.mem.Allocator) void {
std.log.scoped(.deinit).debug("Deinitializing {*} with {*} and Allocator{{{*},{*}}}", .{ self, engine, allocator.ptr, allocator.vtable });
pub fn deinit(self: *Materials) void {
const allocator_general = ctx.allocator_general;
self.material_buffer.deinit(engine);
self.map.deinit(allocator);
std.log.scoped(.deinit).debug("Deinitializing {*}", .{self});
self.material_buffer.deinit();
self.map.deinit(allocator_general);
self.* = undefined;
}
@@ -151,18 +156,15 @@ pub fn getAtom(self: *const Materials, filename: Atom) ?Id {
/// error is not necessarily related to `temp_allocator`.
pub fn getOrLoad(
self: *Materials,
engine: *Engine,
textures: *Textures,
stbi: *media.stbi,
maybe_filename: ?[]const u8,
temp_allocator: std.mem.Allocator,
io: std.Io,
) !Id {
if (maybe_filename) |filename| {
const key: Key = .{
// If the material already exists, then the atom must exist and the
// following line will not return any error.
.filename = try .fromString(filename, io),
.filename = try .fromString(filename),
};
// We don't use `getOrPutAssumeCapacity` method, because we might already be
@@ -174,7 +176,7 @@ pub fn getOrLoad(
const id = Id.fromIndexSafe(self.material_count) catch |err| switch (err) {
error.Overflow => return error.OutOfMaterials,
};
try self.loadMaterial(engine, textures, stbi, filename, id.toInt(), temp_allocator, io);
try self.loadMaterial(textures, stbi, filename, id.toInt());
self.map.putAssumeCapacityNoClobber(key, id);
self.material_count += 1;
@@ -199,12 +201,9 @@ pub fn getOrLoad(
/// error is not necessarily related to `temp_allocator`.
pub fn getOrLoadAtom(
self: *Materials,
engine: *Engine,
textures: *Textures,
stbi: *media.stbi,
filename: Atom,
temp_allocator: std.mem.Allocator,
io: std.Io,
) !Id {
if (filename != .empty) {
const key: Key = .{
@@ -220,7 +219,7 @@ pub fn getOrLoadAtom(
const id = Id.fromIndexSafe(self.material_count) catch |err| switch (err) {
error.Overflow => return error.OutOfMaterials,
};
try self.loadMaterial(engine, textures, stbi, filename.toString(), id.toInt(), temp_allocator, io);
try self.loadMaterial(textures, stbi, filename.toString(), id.toInt());
self.map.putAssumeCapacityNoClobber(key, id);
self.material_count += 1;
@@ -242,14 +241,20 @@ pub fn getOrLoadAtom(
/// deinitialized or reset after this function returns. Note that during loading
/// the engine will make its own persistent allocations, so an out of memory
/// error is not necessarily related to `temp_allocator`.
pub fn loadAll(self: *Materials, engine: *Engine, textures: *Textures, stbi: *media.stbi, temp_allocator: std.mem.Allocator) void {
const cwd = std.fs.cwd();
pub fn loadAll(
self: *Materials,
textures: *Textures,
stbi: *media.stbi,
) void {
const io = ctx.io;
var dir = cwd.openDir("assets/materials", .{ .iterate = true }) catch |err| {
const cwd = std.Io.Dir.cwd();
var dir = cwd.openDir(io, "assets/materials", .{ .iterate = true }) catch |err| {
std.log.err("Error while opening metarials directory: {s}", .{@errorName(err)});
return;
};
defer dir.close();
defer dir.close(io);
var it = dir.iterate();
while (it.next() catch |err| {
@@ -261,13 +266,16 @@ pub fn loadAll(self: *Materials, engine: *Engine, textures: *Textures, stbi: *me
continue;
}
_ = self.getOrLoad(engine, textures, stbi, entry.name, temp_allocator) catch |err| {
_ = self.getOrLoad(textures, stbi, entry.name) catch |err| {
std.log.err("Error while loading material entry {s}: {s}", .{ entry.name, @errorName(err) });
};
}
}
fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, stbi: *media.stbi, filename: []const u8, index: u32, temp_allocator: std.mem.Allocator, io: std.Io) !void {
fn loadMaterial(self: *Materials, textures: *Textures, stbi: *media.stbi, filename: []const u8, index: u32) !void {
const allocator_frame = ctx.allocator_frame;
const io = ctx.io;
const MaterialJson = struct {
baseColor: [3]f32 = .{ 1, 1, 1 },
baseColorTexture: ?[]const u8 = null,
@@ -296,19 +304,15 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, stbi: *m
defer file.close(io);
var file_reader = file.reader(io, &buffer);
var json_reader = std.json.Reader.init(temp_allocator, &file_reader.interface);
defer json_reader.deinit();
var json_reader = std.json.Reader.init(allocator_frame, &file_reader.interface);
const parsed: std.json.Parsed(MaterialJson) = try std.json.parseFromTokenSource(MaterialJson, temp_allocator, &json_reader, .{
const material_json = try std.json.parseFromTokenSourceLeaky(MaterialJson, allocator_frame, &json_reader, .{
.duplicate_field_behavior = .@"error",
.ignore_unknown_fields = false,
.allocate = .alloc_if_needed,
});
defer parsed.deinit();
const material_json = parsed.value;
try self.material_buffer.write(engine, .{
try self.material_buffer.write(.{
.element_offset = index,
.elements = &.{
.{
@@ -319,10 +323,10 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, stbi: *m
.normal_scale = material_json.normalScale,
.occlusion_texture_strength = material_json.occlusionTextureStrength,
.roughness = material_json.roughness,
.base_color_texture = try textures.getOrLoad(engine, stbi, material_json.baseColorTexture, .base_color, io),
.emissive_texture = try textures.getOrLoad(engine, stbi, material_json.emissiveTexture, .emissive, io),
.normal_texture = try textures.getOrLoad(engine, stbi, material_json.normalTexture, .normal, io),
.occlusion_roughness_metallic_texture = try textures.getOrLoad(engine, stbi, material_json.occlusionRoughnessMetallicTexture, .occlusion_roughness_metallic, io),
.base_color_texture = try textures.getOrLoad(stbi, material_json.baseColorTexture, .base_color),
.emissive_texture = try textures.getOrLoad(stbi, material_json.emissiveTexture, .emissive),
.normal_texture = try textures.getOrLoad(stbi, material_json.normalTexture, .normal),
.occlusion_roughness_metallic_texture = try textures.getOrLoad(stbi, material_json.occlusionRoughnessMetallicTexture, .occlusion_roughness_metallic),
},
},
});

View File

@@ -3,6 +3,7 @@
const Textures = @This();
const std = @import("std");
const ctx = @import("../AppContext.zig");
const media = @import("media");
const Atom = @import("../engine/Atom.zig").Atom;
@@ -56,31 +57,34 @@ pub const Key = struct {
usage: Texture.Usage,
};
/// Maps a key value to a texture ID.
/// Maps a key value to a texture ID. Preallocated with `allocator_general`.
map: std.AutoHashMapUnmanaged(Key, Id),
/// Stores all `Texture` structs and maps a texture ID to a `Texture` struct.
/// Preallocated with `allocator_general`.
array: std.ArrayList(Texture),
/// 4096 textures of usage `.base_color` and 16×16 dimensions should take 4 MiB
/// in VRAM.
pub const max_textures = 4096;
pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
var map: std.AutoHashMapUnmanaged(Key, Id) = .empty;
errdefer map.deinit(allocator);
try map.ensureTotalCapacity(allocator, max_textures);
pub fn init() !Textures {
const allocator_general = ctx.allocator_general;
var array: std.ArrayList(Texture) = try .initCapacity(allocator, max_textures);
var map: std.AutoHashMapUnmanaged(Key, Id) = .empty;
errdefer map.deinit(allocator_general);
try map.ensureTotalCapacity(allocator_general, max_textures);
var array: std.ArrayList(Texture) = try .initCapacity(allocator_general, max_textures);
errdefer {
for (array.items) |*texture| {
texture.deinit(engine);
texture.deinit();
}
array.deinit(allocator);
array.deinit(allocator_general);
}
// VOLATILE Synchronize with explicit values on top of `Id` type.
const empty_base_color_texture = try Texture.init(engine, .{
const empty_base_color_texture = try Texture.init(.{
.width = 1,
.height = 1,
.usage = .base_color,
@@ -89,7 +93,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
});
array.appendAssumeCapacity(empty_base_color_texture);
const empty_emissive_texture = try Texture.init(engine, .{
const empty_emissive_texture = try Texture.init(.{
.width = 1,
.height = 1,
.usage = .emissive,
@@ -98,7 +102,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
});
array.appendAssumeCapacity(empty_emissive_texture);
const empty_normal_texture = try Texture.init(engine, .{
const empty_normal_texture = try Texture.init(.{
.width = 1,
.height = 1,
.usage = .normal,
@@ -107,7 +111,7 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
});
array.appendAssumeCapacity(empty_normal_texture);
const empty_occlusuion_roughness_metallic_texture = try Texture.init(engine, .{
const empty_occlusuion_roughness_metallic_texture = try Texture.init(.{
.width = 1,
.height = 1,
.usage = .occlusion_roughness_metallic,
@@ -116,10 +120,10 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
});
array.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 });
try empty_normal_texture.writeSamples(i8, engine, &.{ 0, 0, 127, 127 });
try empty_occlusuion_roughness_metallic_texture.writeSamples(u8, engine, &.{ 255, 255, 255, 255 });
try empty_base_color_texture.writeSamples(u8, &.{ 255, 255, 255, 255 });
try empty_emissive_texture.writeSamples(f16, &.{ 1.0, 1.0, 1.0, 1.0 });
try empty_normal_texture.writeSamples(i8, &.{ 0, 0, 127, 127 });
try empty_occlusuion_roughness_metallic_texture.writeSamples(u8, &.{ 255, 255, 255, 255 });
return .{
.map = map,
@@ -127,14 +131,16 @@ pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Textures {
};
}
pub fn deinit(self: *Textures, engine: *Engine, allocator: std.mem.Allocator) void {
std.log.scoped(.deinit).debug("Deinitializing {*} with {*} and Allocator{{{*},{*}}}", .{ self, engine, allocator.ptr, allocator.vtable });
pub fn deinit(self: *Textures) void {
const allocator_general = ctx.allocator_general;
std.log.scoped(.deinit).debug("Deinitializing {*}", .{self});
for (self.array.items) |*texture| {
texture.deinit(engine);
texture.deinit();
}
self.array.deinit(allocator);
self.map.deinit(allocator);
self.array.deinit(allocator_general);
self.map.deinit(allocator_general);
self.* = undefined;
}
@@ -174,17 +180,15 @@ pub fn getAtom(self: *const Textures, filename: Atom, usage: Texture.Usage) ?Id
/// usage.
pub fn getOrLoad(
self: *Textures,
engine: *Engine,
stbi: *media.stbi,
maybe_filename: ?[]const u8,
usage: Texture.Usage,
io: std.Io,
) !Id {
if (maybe_filename) |filename| {
const key: Key = .{
// If the texture already exists, then the atom must exist and the
// following line will not return any error.
.filename = try .fromString(filename, io),
.filename = try .fromString(filename),
.usage = usage,
};
@@ -197,7 +201,7 @@ pub fn getOrLoad(
const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) {
error.Overflow => return error.OutOfTextures,
};
const texture = try loadTexture(engine, stbi, filename, usage, io);
const texture = try loadTexture(stbi, filename, usage);
self.map.putAssumeCapacityNoClobber(key, id);
self.array.appendAssumeCapacity(texture);
@@ -216,11 +220,9 @@ pub fn getOrLoad(
/// usage.
pub fn getOrLoadAtom(
self: *Textures,
engine: *Engine,
stbi: *media.stbi,
filename: Atom,
usage: Texture.Usage,
io: std.Io,
) !Id {
if (filename != .empty) {
const key: Key = .{
@@ -237,7 +239,7 @@ pub fn getOrLoadAtom(
const id = Id.fromIndexSafe(self.array.items.len) catch |err| switch (err) {
error.Overflow => return error.OutOfTextures,
};
const texture = try loadTexture(engine, stbi, filename.toString(), usage, io);
const texture = try loadTexture(stbi, filename.toString(), usage);
self.map.putAssumeCapacityNoClobber(key, id);
self.array.appendAssumeCapacity(texture);
@@ -250,12 +252,12 @@ pub fn getOrLoadAtom(
}
fn loadTexture(
engine: *Engine,
stbi: *media.stbi,
filename: []const u8,
usage: Texture.Usage,
io: std.Io,
) !Texture {
const io = ctx.io;
std.log.debug("Loading texture \"{s}\" as {s}...", .{ filename, @tagName(usage) });
const cwd = std.Io.Dir.cwd();
@@ -285,16 +287,16 @@ fn loadTexture(
}
}
var texture = try Texture.init(engine, .{
var texture = try Texture.init(.{
.width = img.width,
.height = img.height,
.usage = usage,
.target_queue = .graphics,
.name = filename,
});
errdefer texture.deinit(engine);
errdefer texture.deinit();
try texture.writeRaw(engine, @ptrCast(data));
try texture.writeRaw(@ptrCast(data));
return texture;
}