#include "assets.h" #include "debug.h" #include #include #include typedef struct AssetData { void* asset; asset_id id; AssetDestructor destructor; } AssetData; cJSON* g_levels_json; static AssetData* _assets = NULL; static size_t _assets_len = 0; static size_t _assets_cap = 0; static asset_id _next_id = 0; static size_t file_length(FILE* fp) { size_t start = ftell(fp); fseek(fp, 0, SEEK_END); size_t r = ftell(fp); fseek(fp, start, SEEK_SET); return r; } static void read_file(FILE* fp, char* out_buffer, size_t out_size) { size_t start = ftell(fp); fread(out_buffer, 1, out_size, fp); fseek(fp, start, SEEK_SET); } static void _resize_if_needed(size_t requested_len) { if(requested_len < _assets_cap) { return; // not needed. } size_t new_cap = _assets_cap ? _assets_cap : 8; while(new_cap < requested_len) { new_cap *= 2; } AssetData* new_assets = realloc(_assets, new_cap * sizeof(AssetData)); if(new_assets != NULL) { _assets = new_assets; _assets_cap = new_cap; } } void assets_init() { LOG_INFO("assets_init"); _assets = malloc(_assets_cap * sizeof(AssetData)); _next_id = 1; g_levels_json = load_json_from_file("assets/levels/levels.ldtk"); } // clear all assets without shrinking the assets array. static void _empty_assets() { AssetData* start = _assets; AssetData* end = _assets + _assets_len; for(AssetData* asset = start; asset < end; ++asset) { asset->destructor(asset->asset); } _assets_len = 0; } void assets_clean() { _empty_assets(); free(_assets); _assets_len = 0; _assets_cap = 0; _assets = NULL; cJSON_Delete(g_levels_json); g_levels_json = NULL; } void assets_reset() { _empty_assets(); size_t desired = 8; AssetData* new = realloc(_assets, desired * sizeof(AssetData)); if(new == NULL) return; _assets_cap = desired; _assets = new; } asset_id store_asset(void* asset, AssetDestructor destructor) { _resize_if_needed(_assets_len + 1); AssetData* data = _assets + _assets_len; data->asset = asset; data->destructor = destructor; data->id = _next_id; ++_next_id; ++_assets_len; return data->id; } static AssetData* _internal_get_by_id(asset_id id) { ASSERT_RETURN_WARN(id != 0, NULL, "Cannot get element with id 0"); for(size_t i = 0; i < _assets_len; ++i) { if(_assets[i].id == id) { return _assets + i; } } RETURN_WARNING(NULL, "Failed to find requested asset with id %zu", id); } void* get_asset(asset_id id) { AssetData* found = _internal_get_by_id(id); ASSERT_RETURN(found != NULL, NULL, "Failed to find asset with id %zu.", id); return found; } asset_id get_asset_id(void* asset) { for(size_t i = 0; i < _assets_len; ++i) { if(_assets[i].asset == asset) { return _assets[i].id; } } RETURN_WARNING(0, "Failed to find asset referencing %p", asset); } void free_asset(asset_id id) { AssetData* found = _internal_get_by_id(id); ASSERT_RETURN(found != NULL,, "Attempt to free nonexistent asset."); found->destructor(found->asset); AssetData* next = found + 1; size_t dif = next - (_assets + _assets_len); memmove(found, next, dif); --_assets_len; } cJSON* load_json_from_file(const char* filename) { FILE* fp = fopen(filename, "r"); ASSERT_RETURN(fp != NULL, NULL, "Failed to open file %s.", filename); size_t len = file_length(fp); char* buffer = malloc(len + 1); ASSERT_RETURN(buffer != NULL, NULL, "Failed to allocate buffer for json string."); read_file(fp, buffer, len); cJSON* out = cJSON_Parse(buffer); free(buffer); ASSERT_RETURN(out != NULL, NULL, "Failed to parse json from file %s.", filename); return out; } size_t json_array_len(cJSON* json) { ASSERT_RETURN(cJSON_IsArray(json), 0, "Tried to get the length of a non-array json element."); size_t len = 0; cJSON* itr; cJSON_ArrayForEach(itr, json) { ++len; } return len; }