176 lines
5 KiB
C
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;
|
|
} |