GameEngine API to allow for loading and removing assets as well as rendering textures using their AssetID
204 lines
4.1 KiB
C
204 lines
4.1 KiB
C
#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 <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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;
|
|
}
|