mach: ResourceManager: implement auto convertion of files into assets based on given info

This commit is contained in:
iddev5 2022-06-20 23:20:09 +05:30 committed by Stephen Gutekanst
parent b0a00c5581
commit 71b25dc2a6

View file

@ -5,28 +5,41 @@ const ResourceManager = @This();
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
paths: []const []const u8, paths: []const []const u8,
resource_types: []const ResourceType, // TODO: Use comptime hash map for resource_types
resource_map: std.StringArrayHashMapUnmanaged(ResourceType) = .{},
resources: std.StringHashMapUnmanaged(Resource) = .{}, resources: std.StringHashMapUnmanaged(Resource) = .{},
cwd: std.fs.Dir, cwd: std.fs.Dir,
context: ?*anyopaque = null,
pub fn init(allocator: std.mem.Allocator, paths: []const []const u8, resource_types: []const ResourceType) !ResourceManager { pub fn init(allocator: std.mem.Allocator, paths: []const []const u8, resource_types: []const ResourceType) !ResourceManager {
var cwd = try std.fs.openDirAbsolute(try std.fs.selfExeDirPathAlloc(allocator), .{}); var cwd = try std.fs.openDirAbsolute(try std.fs.selfExeDirPathAlloc(allocator), .{});
errdefer cwd.close(); errdefer cwd.close();
var resource_map: std.StringArrayHashMapUnmanaged(ResourceType) = .{};
for (resource_types) |res| {
try resource_map.put(allocator, res.name, res);
}
return ResourceManager{ return ResourceManager{
.allocator = allocator, .allocator = allocator,
.paths = paths, .paths = paths,
.resource_types = resource_types, .resource_map = resource_map,
.cwd = cwd, .cwd = cwd,
}; };
} }
pub const ResourceType = struct { pub const ResourceType = struct {
name: []const u8, name: []const u8,
load: fn (context: *anyopaque, mem: []const u8) error{ InvalidResource, CorruptData }!*anyopaque, load: fn (context: ?*anyopaque, mem: []const u8) error{ InvalidResource, CorruptData }!*anyopaque,
unload: fn (context: *anyopaque, resource: *anyopaque) void, unload: fn (context: ?*anyopaque, resource: *anyopaque) void,
}; };
pub fn setLoadContext(self: *ResourceManager, ctx: anytype) void {
var context = self.allocator.create(@TypeOf(ctx)) catch unreachable;
context.* = ctx;
self.context = context;
}
pub fn getResource(self: *ResourceManager, uri: []const u8) !Resource { pub fn getResource(self: *ResourceManager, uri: []const u8) !Resource {
if (self.resources.get(uri)) |res| if (self.resources.get(uri)) |res|
return res; return res;
@ -46,22 +59,33 @@ pub fn getResource(self: *ResourceManager, uri: []const u8) !Resource {
} }
if (file) |f| { if (file) |f| {
var data = try f.reader().readAllAlloc(self.allocator, std.math.maxInt(usize)); if (self.resource_map.get(uri_data.scheme)) |res_type| {
errdefer self.allocator.free(data); var data = try f.reader().readAllAlloc(self.allocator, std.math.maxInt(usize));
errdefer self.allocator.free(data);
const res = Resource{ const resource = try res_type.load(self.context, data);
.uri = try self.allocator.dupe(u8, uri), errdefer res_type.unload(self.context, resource);
.resource = @ptrCast(*anyopaque, &data.ptr),
.size = data.len, const res = Resource{
}; .uri = try self.allocator.dupe(u8, uri),
try self.resources.putNoClobber(self.allocator, uri, res); .resource = resource,
return res; .size = data.len,
};
try self.resources.putNoClobber(self.allocator, uri, res);
return res;
}
return error.UnknownResourceType;
} }
return error.ResourceNotFound; return error.ResourceNotFound;
} }
pub fn unloadResource(self: *ResourceManager, res: Resource) void { pub fn unloadResource(self: *ResourceManager, res: Resource) void {
const uri_data = uri_parser.parseUri(res.uri) catch unreachable;
if (self.resource_map.get(uri_data.scheme)) |res_type| {
res_type.unload(self.context, res.resource);
}
_ = self.resources.remove(res.uri); _ = self.resources.remove(res.uri);
} }