#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; }