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