#include "asset.hpp" extern "C" { #include "memory.h" #include "pack.h" #include "plat.h" #include "str.h" } #define max_asset_types 32 #define asset_scratch_size (1024) struct RLoader { char magic[4]; Asset_Loader* loader; }; struct Manager { RLoader loaders[max_asset_types]; Manager() { int i; for (i = 0; i < max_asset_types; i++) { loaders[i].loader = 0; } } RLoader* find_loader(const char* magic) { uint32_t hash = fnv1a64((uint8_t*)magic, 4); int bucket = (int)(hash % max_asset_types); int i; for (i = 0; i < max_asset_types; i++) { RLoader& e = loaders[bucket]; if (!e.loader || ( e.magic[0] == magic[0] && e.magic[1] == magic[1] && e.magic[2] == magic[2] && e.magic[3] == magic[3] )) return &e; bucket = (bucket + 1) % max_asset_types; } return 0; } Asset_Loader& get_loader(const char* magic) { RLoader* r = find_loader(magic); assert(r != 0 && r->loader != 0); return *r->loader; } void set_loader(const char* magic, Asset_Loader* l) { RLoader* r = find_loader(magic); assert(r != 0 && r->loader == 0); r->magic[0] = magic[0]; r->magic[1] = magic[1]; r->magic[2] = magic[2]; r->magic[3] = magic[3]; r->loader = l; } } manager; void register_asset_loader( const char* magic, Asset_Loader* loader ) { manager.set_loader(magic, loader); } void Asset_Arena::init( Arena* arena, const char* pack_name, int max ) { int i; p = pack_open(pack_name, arena); assert(p != 0); a = arena; max_assets = max; assets = (Bucket*)arena_alloc(arena, max * sizeof(Bucket)); for (i = 0; i < max; i++) assets[i].name = 0; } void Asset_Arena::destroy() { int i, c = max_assets; for (i = 0; i < c; i++) { Bucket& b = assets[i]; if (b.name) b.asset->loader->unload(b.asset); } pack_close(p); } int Asset_Arena::bucket(const char* name) { uint32_t hash = hash_string(name); int bucket = (int)(hash % max_assets); int i; for (i = 0; i < max_assets; i++) { Bucket& b = assets[bucket]; if (!b.name || string_equal(name, b.name)) return bucket; bucket = (bucket + 1) % max_assets; } return -1; } Asset* Asset_Arena::load(const char* name) { char magic[4]; char scratch[asset_scratch_size]; Arena sa; Pack_File* f; int b = bucket(name); assert(b >= 0); if (assets[b].name) return assets[b].asset; f = pack_open_file(p, name); if (!f) return 0; pack_read(f, magic, 4); pack_seek(f, 0, seek_rel_start); Asset_Loader& loader = manager.get_loader(magic); init_arena(&sa, scratch, sizeof scratch); Asset* asset = loader.load(a, &sa, name, f); if (asset) { asset->loader = &loader; assets[b].name = dup_string(a, name); assets[b].asset = asset; } pack_close_file(f); return asset; }