Hey everyone,
I am trying to build a simple asset loader for my games. I’ve tried loading some assets from a folder and automatically fetch the basename of a file and use it as the key for my Hashmap entry.
Whenever I am trying to access my data via key I get a null reference error.
I’ve checked the key entries and they’re just empty strings.
Do I have to allocate memory for my keys and later solve free them or is there maybe a better solution?
I came across this issue already twice I think but I couldn’t come up with an elegant solution to my problem.
const std = @import("std");
const rl = @import("raylib");
const Self = @This();
allocator: std.mem.Allocator,
fonts: std.StringArrayHashMapUnmanaged(rl.Font),
shaders: std.StringArrayHashMapUnmanaged(rl.Shader),
textures: std.StringArrayHashMapUnmanaged(rl.Texture2D),
sounds: std.StringArrayHashMapUnmanaged(rl.Sound),
models: std.StringArrayHashMapUnmanaged(rl.Model),
// TODO(MO): does this need to be a heap allocated struct?
pub fn createInit(allocator: std.mem.Allocator) !*Self {
const self = try allocator.create(Self);
const fonts = std.StringArrayHashMapUnmanaged(rl.Font){};
const shaders = std.StringArrayHashMapUnmanaged(rl.Shader){};
const textures = std.StringArrayHashMapUnmanaged(rl.Texture2D){};
const sounds = std.StringArrayHashMapUnmanaged(rl.Sound){};
const models = std.StringArrayHashMapUnmanaged(rl.Model){};
self.* = .{
.allocator = allocator,
.fonts = fonts,
.shaders = shaders,
.textures = textures,
.sounds = sounds,
.models = models,
};
return self;
}
pub fn deinit(self: *Self) void {
self.fonts.deinit(self.allocator);
self.models.deinit(self.allocator);
self.shaders.deinit(self.allocator);
self.textures.deinit(self.allocator);
self.textures.deinit(self.allocator);
self.sounds.deinit(self.allocator);
self.allocator.destroy(self);
}
pub fn loadFromFolder(self: *Self, folder: []const u8) !void {
const dir = try std.fs.openDirAbsolute(folder, .{ .iterate = true });
var walker = try dir.walk(self.allocator);
defer walker.deinit();
while (try walker.next()) |entry| {
// we only care about files
// NOTE: don't iterate depper!
if (entry.kind != .file)
continue;
const basename = entry.basename;
const path = entry.path;
if (std.mem.endsWith(u8, basename, ".ttf")) {
const key = basename;
const font_path = try std.fs.path.joinZ(self.allocator, &[_][]const u8{ folder, path });
defer self.allocator.free(font_path);
const font = rl.loadFont(font_path);
try self.fonts.put(self.allocator, key, font);
} else if (std.mem.endsWith(u8, basename, ".png")) {
const key = basename;
const texture_path = try std.fs.path.joinZ(self.allocator, &[_][]const u8{ folder, path });
defer self.allocator.free(texture_path);
const texture = rl.loadTexture(texture_path);
try self.textures.put(self.allocator, key, texture);
} else if (std.mem.endsWith(u8, basename, ".ogg")) {
const key = basename;
const sound_path = try std.fs.path.joinZ(self.allocator, &[_][]const u8{ folder, path });
defer self.allocator.free(sound_path);
const sound = rl.loadSound(sound_path);
try self.sounds.put(self.allocator, key, sound);
}
}
}