enum ResourceType { ResourceType_invalid, ResourceType_image, ResourceType_font };
struct LoadedResource {
alias_InlineList list;
enum ResourceType type;
uint32_t id, gen;
union {
struct Image image;
struct Font font;
};
};
static alias_InlineList _resource_list_free = ALIAS_INLINE_LIST_INIT(_resource_list_free);
static alias_InlineList _resource_list_inactive = ALIAS_INLINE_LIST_INIT(_resource_list_inactive);
static alias_InlineList _resource_list_active = ALIAS_INLINE_LIST_INIT(_resource_list_active);
static alias_Vector(struct LoadedResource *) _resource_list = ALIAS_VECTOR_INIT;
static uint32_t _resource_id = 1, _resource_gen = 1;
static void _resource_free(struct LoadedResource * resource) {
switch(resource->type) {
case ResourceType_image:
_image_unload(&resource->image);
break;
default:
break;
}
alias_InlineList_remove_self(&resource->list);
alias_InlineList_push(&_resource_list_free, &resource->list);
_resource_list.data[resource->id - 1] = NULL;
}
static void _resource_gc(void) {
struct LoadedResource * resource, * next_resource;
ALIAS_INLINE_LIST_EACH_CONTAINER_SAFE(&_resource_list_inactive, resource, next_resource, list) {
_resource_free(resource);
}
alias_InlineList_push_list(&_resource_list_inactive, &_resource_list_active);
_resource_gen++;
}
static struct LoadedResource * _resource_allocate(enum ResourceType type) {
struct LoadedResource * resource;
if(alias_InlineList_is_empty(&_resource_list_free)) {
resource = alias_malloc(alias_default_MemoryCB(), sizeof(*resource), alignof(*resource));
alias_InlineList_init(&resource->list);
resource->id = _resource_id++;
alias_Vector_space_for(&_resource_list, alias_default_MemoryCB(), 1);
*alias_Vector_push(&_resource_list) = NULL;
} else {
resource = ALIAS_INLINE_LIST_CONTAINER(alias_InlineList_pop(&_resource_list_free), struct LoadedResource, list);
}
alias_InlineList_push(&_resource_list_active, &resource->list);
resource->type = type;
resource->gen = _resource_gen;
_resource_list.data[resource->id - 1] = resource;
return resource;
}
static void _resource_touch(struct LoadedResource * resource) {
if(resource->gen != _resource_gen) {
alias_InlineList_remove_self(&resource->list);
alias_InlineList_push(&_resource_list_active, &resource->list);
resource->gen = _resource_gen;
}
}
static struct LoadedResource * _resource_from_image(struct engine_Image *img) {
struct LoadedResource * resource;
if(img->resource == NULL || img->resource_id != img->resource->id) {
char path[1024];
sprintf(path, sizeof(path), "assets/%s", img->path);
resource = _resource_allocate(ResourceType_image);
_image_load(&resource->image, path);
img->resource = resource;
img->resource_id = resource->id;
} else {
_resource_touch(img->resource);
}
return img->resource;
}
static struct LoadedResource * _resource_from_id(uint32_t id) {
return _resource_list.data[id - 1];
}