Refactor literally everything

This commit is contained in:
2025-11-26 01:19:20 +01:00
parent d6a4b8c1fe
commit 9f2d1e4608
22 changed files with 2070 additions and 1034 deletions

View File

@@ -3,76 +3,112 @@ const std = @import("std");
const vk = @import("vulkan");
const Atoms = @import("Atoms.zig");
const atoms = @import("../engine/atoms.zig");
const Engine = @import("../engine/Engine.zig");
const StorageBuffer = @import("../engine/StorageBuffer.zig");
const GenericBuffer = @import("../engine/GenericBuffer.zig").GenericBuffer;
const Textures = @import("Textures.zig");
allocator: std.mem.Allocator,
const MaterialBuffer = GenericBuffer(void, Material);
map: Map,
storage_buffer: StorageBuffer,
material_buffer: MaterialBuffer,
next_id: Id,
pub const initial_capacity = 4;
// capacity * @sizeOf(Material) = 832 kiB
pub const capacity = std.math.maxInt(std.meta.Tag(Id));
pub const Id = extern struct {
id: u32,
pub const Key = struct { atom: atoms.Atom };
pub const Id = enum(u16) {
_,
pub fn next(self: Id) Id {
return @enumFromInt(@intFromEnum(self) + 1);
}
};
pub const Map = std.AutoHashMapUnmanaged(Atoms.Atom, Id);
pub const Map = std.AutoHashMapUnmanaged(Key, Id);
pub const Material = extern struct {
base_color: [3]f32,
base_color_texture: Textures.Id,
emissive: [3]f32,
emissive_texture: Textures.Id,
ior: f32,
metallic: f32,
normal_scale: f32,
normal_texture: Textures.Id,
occlusion_roughness_metallic_texture: Textures.Id,
occlusion_texture_strength: f32,
roughness: f32,
base_color_texture: Textures.Id,
emissive_texture: Textures.Id,
normal_texture: Textures.Id,
occlusion_roughness_metallic_texture: Textures.Id,
};
pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Materials {
pub fn init(engine: *Engine, allocator: std.mem.Allocator) !Materials {
var map: Map = .empty;
errdefer map.deinit(allocator);
try map.ensureTotalCapacity(allocator, capacity);
var storage_buffer: StorageBuffer = try .init(engine, void, Material, initial_capacity);
errdefer storage_buffer.deinit(engine);
var material_buffer = try MaterialBuffer.init(engine, .{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = capacity,
});
errdefer material_buffer.deinit(engine);
return .{
.allocator = allocator,
.map = map,
.storage_buffer = storage_buffer,
.next_id = .{ .id = 0 },
.material_buffer = material_buffer,
.next_id = @enumFromInt(0),
};
}
pub fn deinit(self: *Materials, engine: *Engine) void {
self.storage_buffer.deinit(engine);
self.map.deinit(self.allocator);
pub fn deinit(self: *Materials, engine: *Engine, allocator: std.mem.Allocator) void {
self.material_buffer.deinit(engine);
self.map.deinit(allocator);
self.* = undefined;
}
pub fn getId(self: *const Materials, key: Atoms.Atom) ?Id {
pub fn getAtom(self: *const Materials, atom: atoms.Atom) ?Id {
const key: Key = .{ .atom = atom };
return self.map.get(key);
}
pub fn getOrLoadId(self: *Materials, engine: *Engine, textures: *Textures, atoms: *Atoms, key: Atoms.Atom) !Id {
const entry = try self.map.getOrPut(self.allocator, key);
pub fn getFilename(self: *const Materials, filename: []const u8) ?Id {
const atom = atoms.getAtom(filename) orelse return null;
const key: Key = .{ .atom = atom };
return self.map.get(key);
}
pub fn getOrLoadAtom(self: *Materials, engine: *Engine, 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 {
const id = try self.loadMaterial(engine, textures, atoms, key);
errdefer _ = self.map.remove(key);
const id = try self.loadMaterial(engine, textures, atoms.getString(atom), temp_allocator);
entry.value_ptr.* = id;
return id;
}
}
fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, atoms: *Atoms, key: Atoms.Atom) !Id {
pub fn getOrLoadFilename(self: *Materials, engine: *Engine, 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 id = try self.loadMaterial(engine, textures, filename, temp_allocator);
entry.value_ptr.* = id;
return id;
}
}
fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, filename: []const u8, temp_allocator: std.mem.Allocator) !Id {
const MaterialJson = struct {
baseColor: [3]f32 = .{ 1, 1, 1 },
baseColorTexture: ?[]const u8 = null,
@@ -87,7 +123,6 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, atoms: *
roughness: f32 = 1,
};
const filename = atoms.getString(key).?;
std.log.debug("Loading material \"{s}\"...", .{filename});
const cwd = std.fs.cwd();
@@ -102,10 +137,10 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, atoms: *
defer file.close();
var file_reader = file.reader(&buffer);
var json_reader: std.json.Reader = .init(self.allocator, &file_reader.interface);
var json_reader: std.json.Reader = .init(temp_allocator, &file_reader.interface);
defer json_reader.deinit();
const parsed: std.json.Parsed(MaterialJson) = try std.json.parseFromTokenSource(MaterialJson, self.allocator, &json_reader, .{
const parsed: std.json.Parsed(MaterialJson) = try std.json.parseFromTokenSource(MaterialJson, temp_allocator, &json_reader, .{
.duplicate_field_behavior = .@"error",
.ignore_unknown_fields = false,
.allocate = .alloc_if_needed,
@@ -116,65 +151,57 @@ fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, atoms: *
const base_color_texture = blk: {
if (material_json.baseColorTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .base_color });
break :blk try textures.getOrLoadFilename(engine, name, .base_color, temp_allocator);
} else {
break :blk textures.empty_base_color;
break :blk .empty_base_color;
}
};
const emissive_texture = blk: {
if (material_json.emissiveTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .emissive });
break :blk try textures.getOrLoadFilename(engine, name, .emissive, temp_allocator);
} else {
break :blk textures.empty_emissive;
break :blk .empty_emissive;
}
};
const normal_texture = blk: {
if (material_json.normalTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .normal });
break :blk try textures.getOrLoadFilename(engine, name, .normal, temp_allocator);
} else {
break :blk textures.empty_normal;
break :blk .empty_normal;
}
};
const occlusion_roughness_metallic_texture = blk: {
if (material_json.occlusionRoughnessMetallicTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .occlusion_roughness_metallic });
break :blk try textures.getOrLoadFilename(engine, name, .occlusion_roughness_metallic, temp_allocator);
} else {
break :blk textures.empty_occlusuion_roughness_metallic;
break :blk .empty_occlusion_roughness_metallic;
}
};
const next_id = self.next_id;
const offset: usize = next_id.id;
if (offset >= self.storage_buffer.array_capacity) {
try self.storage_buffer.enlarge(void, Material, engine, self.storage_buffer.array_capacity * 2);
}
const materials = [_]Material{
.{
.base_color = material_json.baseColor,
.base_color_texture = base_color_texture,
.emissive = material_json.emissive,
.emissive_texture = emissive_texture,
.ior = material_json.ior,
.metallic = material_json.metallic,
.normal_scale = material_json.normalScale,
.normal_texture = normal_texture,
.occlusion_roughness_metallic_texture = occlusion_roughness_metallic_texture,
.occlusion_texture_strength = material_json.occlusionTextureStrength,
.roughness = material_json.roughness,
try self.material_buffer.write(engine, .{
.element_offset = @intFromEnum(self.next_id),
.elements = &.{
.{
.base_color = material_json.baseColor,
.emissive = material_json.emissive,
.ior = material_json.ior,
.metallic = material_json.metallic,
.normal_scale = material_json.normalScale,
.occlusion_texture_strength = material_json.occlusionTextureStrength,
.roughness = material_json.roughness,
.base_color_texture = base_color_texture,
.emissive_texture = emissive_texture,
.normal_texture = normal_texture,
.occlusion_roughness_metallic_texture = occlusion_roughness_metallic_texture,
},
},
};
});
try self.storage_buffer.writeOffset(void, Material, engine, {}, offset, &materials);
self.next_id = .{ .id = next_id.id + 1 };
const id = self.next_id;
self.next_id = self.next_id.next();
return next_id;
return id;
}