fencer/src/tileset.c
2023-10-16 21:31:48 +02:00

176 lines
5 KiB
C

#include "tileset.h"
#include "debug.h"
#include "spritesheet.h"
#include "assets.h"
#include "render.h"
#include "SDL2/SDL_image.h"
struct TileDef {
size_t tid;
Sprite* sprite;
Shape* collision;
};
struct Tileset {
size_t uid;
Spritesheet* atlas;
TileDef* tiledefs;
size_t tiledefs_len;
};
typedef struct TilesetStore {
Tileset* set;
size_t iid;
} TilesetStore;
static TilesetStore* _tilesets = NULL;
static size_t _tilesets_len = 0;
static size_t _tilesets_cap = 0;
static
int _internal_tilesets_resize_if_needed(size_t required_cap) {
if(required_cap < _tilesets_cap) {
return 1;
}
size_t needed = _tilesets_cap ? _tilesets_cap : 2;
while(needed < required_cap) {
needed *= 2;
}
TilesetStore* new = realloc(_tilesets, needed * sizeof(TilesetStore));
if(new == NULL) {
LOG_ERROR("Failed to resize tileset store array.");
return 0;
}
_tilesets_cap = needed;
_tilesets = new;
return 1;
}
static
void _internal_tileset_deallocate(void* self_void) {
Tileset* self = self_void;
TilesetStore* store = _tilesets;
for(; store < _tilesets + _tilesets_len; ++store) {
if(store->set == self) {
break;
}
}
size_t diff = _tilesets_len - (size_t)(store - _tilesets);
memmove(store, store+1, diff-1);
--_tilesets_len;
spritesheet_destroy(self->atlas);
free(self->tiledefs);
}
static
void _internal_tileset_store(Tileset* self) {
_internal_tilesets_resize_if_needed(_tilesets_len + 1);
_tilesets[_tilesets_len].set = self;
_tilesets[_tilesets_len].iid = self->uid;
}
Tileset* tileset_from_json(cJSON* json) {
cJSON* uid = cJSON_GetObjectItem(json, "uid");
ASSERT_RETURN(uid != NULL && cJSON_IsNumber(uid), NULL, "Failed to find uid while loading tileset");
cJSON* path = cJSON_GetObjectItem(json, "relPath");
ASSERT_RETURN(path != NULL && cJSON_IsString(path), NULL, "Failed to find relPath while loading tileset");
cJSON* gridsize = cJSON_GetObjectItem(json, "tileGridSize");
ASSERT_RETURN(gridsize != NULL && cJSON_IsNumber(gridsize), NULL, "Failed to find tileGridSize while loading tileset");
SDL_Surface* atlas_surface = IMG_Load(path->valuestring);
ASSERT_RETURN(atlas_surface != NULL, NULL, "Failed to load atlas image while loading tileset");
Tileset* self = malloc(sizeof(Tileset));
if(self == NULL) {
SDL_FreeSurface(atlas_surface);
RETURN_ERROR(NULL, "Failed to allocate space for new tileset.");
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(g_renderer, atlas_surface);
if(texture == NULL) {
free(self);
SDL_FreeSurface(atlas_surface);
RETURN_ERROR(NULL, "Failed to convert atlas surface to texture");
}
IVector grid = {gridsize->valueint, gridsize->valueint};
_internal_tileset_store(self);
*self = (Tileset) {
.uid = uid->valueint,
.atlas = spritesheet_from_texture(texture, grid),
};
IVector resolution = spritesheet_get_resolution(self->atlas);
self->tiledefs_len = resolution.x / grid.x * resolution.y / grid.y;
self->tiledefs = malloc(self->tiledefs_len * sizeof(TileDef));
LOG_INFO("tiledefs_len: %zu", self->tiledefs_len);
LOG_INFO("resolution: %d, %d", resolution.x, resolution.y);
LOG_INFO("grid: %d, %d", grid.x, grid.y);
for(size_t tid = 0; tid < self->tiledefs_len; ++tid) {
self->tiledefs[tid] = (TileDef) {
.tid = tid,
.sprite = sprite_from_spritesheet(self->atlas, tid),
.collision = shape_new_square(OneVector)
};
sprite_set_origin(self->tiledefs[tid].sprite, ZeroVector);
// TODO: generate/read collision information
}
SDL_FreeSurface(atlas_surface);
return self;
}
Tileset* tileset_load(size_t uid) {
for(TilesetStore* store = _tilesets; store < _tilesets + _tilesets_len; ++store) {
if(store->iid == uid) {
return store->set;
}
}
cJSON* defs = cJSON_GetObjectItem(g_levels_json, "defs");
ASSERT_RETURN(defs != NULL, NULL, "Failed to find defs element in levels json.");
cJSON* tilesets = cJSON_GetObjectItem(defs, "tilesets");
ASSERT_RETURN(tilesets != NULL, NULL, "Failed to find tileset defs region in levels json");
cJSON* tileset = NULL;
cJSON_ArrayForEach(tileset, tilesets) {
cJSON* tileset_uid = cJSON_GetObjectItem(tileset, "uid");
if(tileset_uid == NULL) continue;
LOG_INFO("finding uid: %d", tileset_uid->valueint);
if(uid == tileset_uid->valueint) {
break;
}
}
ASSERT_RETURN(tileset != NULL, NULL, "Failed to find a tileset with the uid matching %zu", uid);
return tileset_from_json(tileset);
}
void tileset_destroy(Tileset* self) {
_internal_tileset_deallocate(self);
}
TileDef* tileset_get_tiledef(Tileset* self, size_t t) {
return &self->tiledefs[t];
}
Sprite* tiledef_get_sprite(const TileDef* self) {
return self->sprite;
}
Shape* tiledef_get_shape(TileDef* self) {
return self->collision;
}