#include "AssetManager.h" #include "Renderer.h" #include "SDL_image.h" #include "SDL_mixer.h" #include "SDL_render.h" #include "constants.h" #include "reusable_ids.h" #include #include #include #include #include typedef struct asset { AssetType type; char *path; union { SDL_Texture *texture; Mix_Chunk *chunk; Mix_Music *music; } data; } Asset; struct asset_manager { size_t count; size_t deleted_count; AssetID reusable_ids[MAX_ASSET_COUNT]; Asset assets[MAX_ASSET_COUNT]; }; AssetManager *create_asset_manager() { AssetManager *am = (AssetManager *)malloc(sizeof(AssetManager)); if (!am) { return NULL; } am->count = 0; am->deleted_count = 0; memset(am->reusable_ids, 0, sizeof(am->reusable_ids)); memset(am->assets, 0, sizeof(am->assets)); return am; } AssetID load_asset_to_manager(AssetManager *am, const char *path, AssetType type, Renderer *renderer) { if (!am || type == ASSET_TYPE_COUNT) { return -1; } Asset asset = {}; bool loaded = true; // TODO (Abdelrahman): Implement a way to make sure that an asset with the // same path is not already loaded. If the user attempts to load an asset // that already exists, the function should return -1 to indicate an error switch (type) { case ASSET_TYPE_IMAGE: if (!renderer) { loaded = false; break; } asset.data.texture = load_texture(renderer, path); if (!(asset.data.texture)) { loaded = false; } break; case ASSET_TYPE_AUDIO_FX: // TODO (Abdelrahman): Implement loading audio chunks break; case ASSET_TYPE_MUSIC: // TODO (Abdelrahman): Implement loading music break; default: loaded = false; break; } if (!loaded) { return -1; } AssetID id; if (am->deleted_count > 0) { id = (AssetID)reuse_id((int32_t *)am->reusable_ids, am->deleted_count); am->deleted_count -= 1; am->count += 1; } else { id = (am->count)++; } am->assets[id].type = type; am->assets[id].path = (char *)malloc(strlen(path) + 1); strcpy(am->assets[id].path, path); am->assets[id].data = asset.data; switch (type) { case ASSET_TYPE_IMAGE: asset.data.texture = NULL; break; case ASSET_TYPE_AUDIO_FX: asset.data.chunk = NULL; break; case ASSET_TYPE_MUSIC: asset.data.music = NULL; break; default: break; } return id; } void remove_asset_from_manager(AssetManager *am, AssetID id) { if (!am || am->count == 0) { return; } free(am->assets[id].path); am->assets[id].path = 0; switch (am->assets[id].type) { case ASSET_TYPE_IMAGE: SDL_DestroyTexture(am->assets[id].data.texture); am->assets[id].data.texture = NULL; break; case ASSET_TYPE_AUDIO_FX: // TODO (Abdelrahman): Implement closing audio chunk break; case ASSET_TYPE_MUSIC: // TODO (Abdelrahman): Implement closing music break; default: break; } am->reusable_ids[(am->deleted_count)++] = id; am->count -= 1; } SDL_Texture *get_texture(AssetManager *am, AssetID id) { if (am->assets[id].type != ASSET_TYPE_IMAGE) { return NULL; } return am->assets[id].data.texture; } Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id) { if (am->assets[id].type != ASSET_TYPE_AUDIO_FX) { return NULL; } return am->assets[id].data.chunk; } Mix_Music *get_music(AssetManager *am, AssetID id) { if (am->assets[id].type != ASSET_TYPE_MUSIC) { return NULL; } return am->assets[id].data.music; } void destroy_asset_manager(AssetManager *am) { if (!am) { return; } for (size_t i = 0; i < am->count; ++i) { free(am->assets[i].path); am->assets[i].path = NULL; switch (am->assets[i].type) { case ASSET_TYPE_IMAGE: SDL_DestroyTexture(am->assets[i].data.texture); am->assets[i].data.texture = NULL; break; case ASSET_TYPE_AUDIO_FX: // TODO (Abdelrahman): Implement closing audio chunk break; case ASSET_TYPE_MUSIC: // TODO (Abdelrahman): Implement closing music break; default: break; } } am->count = 0; am->deleted_count = 0; free(am); am = NULL; }