Loading materials and textures

This commit is contained in:
2025-11-22 00:41:56 +01:00
parent 63a8eee18c
commit bf0224ccd8
16 changed files with 563 additions and 626 deletions

View File

@@ -11,14 +11,14 @@ pub const Atom = extern struct {
};
pub const Map = std.StringHashMapUnmanaged(Atom);
pub const Array = std.ArrayList([]const u16);
pub const Array = std.ArrayList([]const u8);
pub fn init(allocator: std.mem.Allocator) Atoms {
return .{
.allocator = allocator,
.string_arena_state = .{},
.map = .empty,
.next_index = 0,
.array = .empty,
};
}
@@ -44,7 +44,7 @@ pub fn getOrPutAtom(self: *Atoms, string: []const u8) !Atom {
if (entry.found_existing) {
return entry.value_ptr.*;
} else {
errdefer self.map.remove(string);
errdefer _ = self.map.remove(string);
try self.array.ensureUnusedCapacity(self.allocator, 1);
const owned_string = try self.toOwnedString(string);
@@ -60,7 +60,7 @@ pub fn getOrPutAtom(self: *Atoms, string: []const u8) !Atom {
}
}
fn toOwnedString(self: *const Atoms, string: []const u8) ![]const u8 {
fn toOwnedString(self: *Atoms, string: []const u8) ![]const u8 {
var string_arena = self.string_arena_state.promote(std.heap.page_allocator);
defer self.string_arena_state = string_arena.state;

View File

@@ -5,10 +5,15 @@ const vk = @import("vulkan");
const Atoms = @import("Atoms.zig");
const Engine = @import("../engine/Engine.zig");
const StorageBuffer = @import("../engine/StorageBuffer.zig");
const Textures = @import("Textures.zig");
allocator: std.mem.Allocator,
map: Map,
storage_buffer: StorageBuffer,
next_id: Id,
pub const initial_capacity = 4;
pub const Id = extern struct {
id: u32,
@@ -30,22 +35,44 @@ pub const Material = extern struct {
roughness: f32,
};
pub fn init(allocator: std.mem.Allocator) !Materials {
pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Materials {
var map: Map = .empty;
errdefer map.deinit(allocator);
var storage_buffer: StorageBuffer = try .init(engine, void, Material, initial_capacity);
errdefer storage_buffer.deinit(engine);
return .{
.allocator = allocator,
.map = map,
.storage_buffer = storage_buffer,
.next_id = .{ .id = 0 },
};
}
pub fn deinit(self: *Materials) void {
self.arena.deinit();
pub fn deinit(self: *Materials, engine: *Engine) void {
self.storage_buffer.deinit(engine);
self.map.deinit(self.allocator);
self.* = undefined;
}
fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *Atoms, key: Atoms.Atom) !Id {
pub fn getId(self: *const Materials, key: Atoms.Atom) ?Id {
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);
if (entry.found_existing) {
return entry.value_ptr.*;
} else {
const id = try self.loadMaterial(engine, textures, atoms, key);
entry.value_ptr.* = id;
return id;
}
}
fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, atoms: *Atoms, key: Atoms.Atom) !Id {
const MaterialJson = struct {
baseColor: [3]f32 = .{ 1, 1, 1 },
baseColorTexture: ?[]const u8 = null,
@@ -89,7 +116,7 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
const base_color_texture = blk: {
if (material_json.baseColorTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .base_color });
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .base_color });
} else {
break :blk textures.empty_base_color;
}
@@ -98,7 +125,7 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
const emissive_texture = blk: {
if (material_json.emissiveTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .emissive });
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .emissive });
} else {
break :blk textures.empty_emissive;
}
@@ -107,7 +134,7 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
const normal_texture = blk: {
if (material_json.normalTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .normal });
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .normal });
} else {
break :blk textures.empty_normal;
}
@@ -116,23 +143,37 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
const occlusion_roughness_metallic_texture = blk: {
if (material_json.occlusionRoughnessMetallicTexture) |name| {
const atom = try atoms.getOrPutAtom(name);
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .occlusion_roughness_metallic });
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .occlusion_roughness_metallic });
} else {
break :blk textures.empty_occlusuion_roughness_metallic;
}
};
const material: 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,
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.storage_buffer.writeOffset(void, Material, engine, {}, offset, &materials);
self.next_id = .{ .id = next_id.id + 1 };
return next_id;
}

View File

@@ -34,7 +34,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Textures {
var array: Array = try .initCapacity(allocator, 4);
errdefer {
for (array.items) |texture| {
for (array.items) |*texture| {
texture.deinit(engine);
}
array.deinit(allocator);
@@ -56,12 +56,13 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Textures {
const empty_occlusuion_roughness_metallic_texture: Texture = try .init(engine, 1, 1, .occlusion_roughness_metallic);
array.appendAssumeCapacity(empty_occlusuion_roughness_metallic_texture);
empty_base_color_texture.write([3]u8, &.{.{ 255, 255, 255 }});
empty_emissive_texture.write([3]f32, &.{.{ 1.0, 1.0, 1.0 }});
empty_normal_texture.write([3]u8, &.{.{ 128, 128, 255 }});
empty_occlusuion_roughness_metallic_texture.write([3]u8, &.{.{ 255, 255, 255 }});
try empty_base_color_texture.write([4]u8, engine, &.{.{ 255, 255, 255, 255 }});
try empty_emissive_texture.write([4]f16, engine, &.{.{ 1.0, 1.0, 1.0, 1.0 }});
try empty_normal_texture.write([4]u8, engine, &.{.{ 128, 128, 255, 255 }});
try empty_occlusuion_roughness_metallic_texture.write([4]u8, engine, &.{.{ 255, 255, 255, 255 }});
return .{
.allocator = allocator,
.map = map,
.array = array,
@@ -72,13 +73,13 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Textures {
};
}
pub fn deinit(self: *Textures, allocator: std.mem.Allocator, engine: *Engine) void {
for (self.array.items) |texture| {
pub fn deinit(self: *Textures, engine: *Engine) void {
for (self.array.items) |*texture| {
texture.deinit(engine);
}
self.array.deinit(allocator);
self.array.deinit(self.allocator);
self.map.deinit(allocator);
self.map.deinit(self.allocator);
}
pub fn getTexture(self: *const Textures, id: Id) ?*Texture {
@@ -90,15 +91,15 @@ pub fn getId(self: *const Textures, key: Key) ?Id {
return self.map.get(key);
}
pub fn getOrLoadId(self: *Textures, engine: *Engine, key: Key) !Id {
pub fn getOrLoadId(self: *Textures, engine: *Engine, atoms: *Atoms, key: Key) !Id {
const entry = try self.map.getOrPut(self.allocator, key);
if (entry.found_existing) {
return entry.value_ptr.*;
} else {
errdefer self.map.remove(key);
errdefer _ = self.map.remove(key);
try self.array.ensureUnusedCapacity(self.allocator, 1);
const texture = try self.loadTexture(engine, key);
const texture = try self.loadTexture(engine, atoms, key);
const id = self.nextId();
@@ -109,13 +110,14 @@ pub fn getOrLoadId(self: *Textures, engine: *Engine, key: Key) !Id {
}
}
fn loadTexture(self: *Textures, engine: *Engine, key: Key) !Texture {
fn loadTexture(self: *Textures, engine: *Engine, atoms: *Atoms, key: Key) !Texture {
const filename = atoms.getString(key.atom).?;
const cwd = std.fs.cwd();
var dir = try cwd.openDir("assets/textures", .{});
defer dir.close();
const file = try dir.openFile(key.name, .{});
const file = try dir.openFile(filename, .{});
defer file.close();
const file_buf = try file.readToEndAlloc(self.allocator, std.math.maxInt(usize));
@@ -128,7 +130,7 @@ fn loadTexture(self: *Textures, engine: *Engine, key: Key) !Texture {
var texture: Texture = try .init(engine, img.width, img.height, key.usage);
errdefer texture.deinit(engine);
texture.write(u8, img.data);
try texture.write(u8, engine, img.data);
return texture;
}