fencer/src/assets.c

180 lines
4.1 KiB
C

#include "assets.h"
#include "debug.h"
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>
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;
}