#include "asset_manager.h" #include #include #include "linked_list.h" #include "texture.h" #include "memory_alloc.h" #include "errors.h" int create_asset(asset_t *asset, va_list args) { asset->type = va_arg(args, asset_type_t); asset->nb_refs = 0; return EXIT_SUCCESS; } int destroy_asset(asset_t *asset) { free(asset->name); switch(asset->type) { case ASSET_TEXTURE: SDL_DestroyTexture(asset->data); break; default: error_printf("Asset type not valid : %d", asset->type); break; } return EXIT_SUCCESS; } int destroy_asset_header_def(asset_header_def_t *asset_header_def) { free(asset_header_def->name); return EXIT_SUCCESS; } int asset_manager_init(asset_manager_t *asset_manager) { assert("Asset manager cannot be NULL" && asset_manager); linked_list_init(&asset_manager->assets, sizeof(asset_t), (allocator_t)create_asset, (deleter_t)destroy_asset); linked_list_init(&asset_manager->assets_header_defs, sizeof(asset_header_def_t), NULL, (deleter_t)destroy_asset_header_def); asset_manager->asset_file = fopen(ASSET_FILE_NAME, "rb"); if(!asset_manager->asset_file) { error_printf("Failed to open asset file : %d", errno); return EXIT_FAILURE; } size_t nb_assets; size_t ret = fread(&nb_assets, sizeof(nb_assets), 1, asset_manager->asset_file); if(ret != 1) { error_printf("Failed to read asset file."); return EXIT_FAILURE; } if(linked_list_reserve(&asset_manager->assets_header_defs, nb_assets + 1)) return_failure_int; for(size_t i = 0; i < nb_assets; i++) { elem_t *asset_header_def_elem = create_elem(&asset_manager->assets_header_defs); if(!asset_header_def_elem) return_failure_int; asset_header_def_t *asset_header_def = asset_header_def_elem->data; size_t cap = 0; ret = getdelim(&asset_header_def->name, &cap, '\0', asset_manager->asset_file); if(ret == SIZE_MAX) { error_printf("Failed to read asset file."); return EXIT_FAILURE; } ret = fread(&asset_header_def->start, sizeof(asset_header_def->start), 1, asset_manager->asset_file); if(ret != 1) { error_printf("Failed to read asset file."); return EXIT_FAILURE; } linked_list_push_back(&asset_manager->assets_header_defs, asset_header_def_elem); } debug_printf("Initialized asset manager."); return EXIT_SUCCESS; } int asset_manager_exit(asset_manager_t *asset_manager) { assert("Asset manager cannot be NULL" && asset_manager); if(linked_list_exit(&asset_manager->assets_header_defs)) return_failure_int; if(linked_list_exit(&asset_manager->assets)) return_failure_int; if(fclose(asset_manager->asset_file)) { error_printf("Failed to close asset file : %d", errno); return EXIT_FAILURE; } debug_printf("Exited asset manager."); return EXIT_SUCCESS; } // Only for this file // No args static inline bool condition_is_asset_unused(elem_t *elem, va_list args __attribute__((unused))) { return !((asset_t *)elem->data)->nb_refs; } inline int asset_manager_collect_garbage(asset_manager_t *asset_manager) { assert("Asset manager cannot be NULL" && asset_manager); if(linked_list_remove_if(&asset_manager->assets, condition_is_asset_unused)) return_failure_int; return EXIT_SUCCESS; } // Only for this file // Arg : const char *asset_name static inline bool condition_is_asset_name(elem_t *elem, va_list args) { return !strcmp(((asset_t *)elem->data)->name, va_arg(args, const char *)); } //Only for this file // Arg : const char *asset_name static inline bool condition_is_asset_header_def_name(elem_t *elem, va_list args) { return !strcmp(((asset_header_def_t *)elem->data)->name, va_arg(args, const char *)); } asset_t *asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_name, asset_type_t asset_type) { assert("Asset manager cannot be NULL" && asset_manager); // Check if asset has alread been loaded. elem_t *asset_elem = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name); if(asset_elem) { ((asset_t *)asset_elem->data)->nb_refs++; debug_printf("Asset \"%s\" has already been loaded, nb refs : %lu", ((asset_t *)asset_elem->data)->name, ((asset_t *)asset_elem->data)->nb_refs); } else { // If it didn't, load it elem_t *asset_header_def_elem = linked_list_get_if(&asset_manager->assets_header_defs, condition_is_asset_header_def_name, asset_name); if(!asset_header_def_elem) { error_printf("Asset doesn't exist in asset file : %s", asset_name); return NULL; } asset_header_def_t *asset_header_def = asset_header_def_elem->data; asset_elem = create_elem(&asset_manager->assets, asset_type); if(!asset_elem) return_failure_ptr; asset_t *asset = asset_elem->data; asset->name = calloc(strlen(asset_name) + 1, sizeof(char)); if(!asset->name) { error_printf("Failed to allocate memory for asset name : %d", errno); destroy_asset(asset); return NULL; } strcpy(asset->name, asset_name); asset->type = asset_type; if(fseek(asset_manager->asset_file, asset_header_def->start, SEEK_SET)) { error_printf("Failed to seek in asset file : %d", errno); return NULL; } switch(asset_type) { case ASSET_TEXTURE: asset->data = texture_load(asset_manager->asset_file); if(!asset->data) return_failure_ptr; break; default: error_printf("Asset type doesn't exists : %d", asset_type); destroy_asset(asset); return NULL; } asset->nb_refs++; linked_list_push_back(&asset_manager->assets, asset_elem); debug_printf("Asset \"%s\" has been loaded, nb refs : %lu", asset->name, asset->nb_refs); } return asset_elem->data; } int asset_manager_let_go_asset(asset_manager_t *asset_manager, const char *asset_name) { assert("Asset manager cannot be NULL" && asset_manager); elem_t *asset_elem = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name); if(!asset_elem) { error_printf("Asset doesn't exists : %s", asset_name); return EXIT_FAILURE; } asset_t *asset = asset_elem->data; asset->nb_refs--; debug_printf("Asset \"%s\" has been let go, nb refs : %lu", asset->name, asset->nb_refs); return EXIT_SUCCESS; } asset_t *asset_manager_get_asset(asset_manager_t *asset_manager, const char *texture_name) { assert("Asset manager cannot be NULL" && asset_manager); elem_t *asset_elem = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, texture_name); if(!asset_elem) { error_printf("Asset \"%s\" hasn't been loaded yet.", texture_name); return NULL; } return asset_elem->data; }