From e304b0a4acc3f0870f55e6b584c464096333dfdc Mon Sep 17 00:00:00 2001 From: zlago Date: Fri, 27 Sep 2024 18:34:24 +0200 Subject: tilemap collision the 'middle ground' layer is the only layer which is solid, and the boundary between the background and the foreground additionally, the maps now can have a custom sky color --- src/main.c | 15 ++++++------ src/res/untitled.tmx | 5 +++- src/tilemap.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++------ src/tilemap.h | 15 ++++++++---- utl/json2map/main.c | 50 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 21 deletions(-) diff --git a/src/main.c b/src/main.c index 6da4d9a..eccd351 100644 --- a/src/main.c +++ b/src/main.c @@ -46,6 +46,7 @@ int main(int argc, char **argv) { goto end; } SDL_RenderSetLogicalSize(renderer, WINDOW_WIDTH, WINDOW_HEIGHT); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); { res_init(); @@ -57,7 +58,7 @@ int main(int argc, char **argv) { } free(a); struct blob map = res_get_map("untitled"); - tilemap = load_tilemap(map.data, map.size); + tilemap = tilemap_load(map.data, map.size); printf("load_tilemap %p\n", (void *) tilemap); SDL_SetRenderTarget(renderer, NULL); } @@ -125,6 +126,8 @@ int main(int argc, char **argv) { case SDL_MOUSEWHEEL: // the scroll wheel gets rolled //fprintf(stderr, "scrolled by %2i %2i %4.1f %4.1f\n", evt.wheel.x, evt.wheel.y, evt.wheel.preciseX, evt.wheel.preciseY); break; + case SDL_CLIPBOARDUPDATE: // annoying + break; case SDL_WINDOWEVENT: // window related events switch (evt.window.event) { case SDL_WINDOWEVENT_SHOWN: @@ -179,9 +182,6 @@ int main(int argc, char **argv) { SDL_SetRenderTarget(renderer, NULL); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); - SDL_SetRenderDrawColor(renderer, 0, 128, 255, 0); - SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); - SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); x += input_right(input_now) - input_left(input_now); y += input_down(input_now) - input_up(input_now); @@ -189,16 +189,15 @@ int main(int argc, char **argv) { if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;} //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); - for (int i = 0; i < tilemap->layers; i++) { - SDL_RenderCopy(renderer, tilemap->tilemaps[i], &(SDL_Rect) {x * tilemap->parallax[i].x, y * tilemap->parallax[i].y, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); - } + tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); + tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); // then we wait for the next video frame SDL_RenderPresent(renderer); } end: - free_tilemap(tilemap), tilemap = NULL; + tilemap_free(tilemap), tilemap = NULL; SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); //SDL_QuitSubSystem(INIT_SUBSYSTEMS); diff --git a/src/res/untitled.tmx b/src/res/untitled.tmx index 51b506c..6a8bbd0 100644 --- a/src/res/untitled.tmx +++ b/src/res/untitled.tmx @@ -1,5 +1,5 @@ - + @@ -32,6 +32,9 @@ + + + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, diff --git a/src/tilemap.c b/src/tilemap.c index 84d2509..af2c163 100644 --- a/src/tilemap.c +++ b/src/tilemap.c @@ -14,19 +14,40 @@ struct tilemap *tilemap = NULL, *next_tilemap = NULL; #define PACKED __attribute__((__packed__)) +uint8_t const MAGIC[4] = "TMv1"; + struct PACKED sets { + uint8_t magic[4]; uint32_t tilesets_count; uint32_t wang_count; }; struct PACKED map { + struct { + uint8_t r, g, b, a; + } backdrop; uint32_t width; uint32_t height; uint32_t layers; + uint32_t middleground; uint8_t tiles[]; }; -void free_tilemap(struct tilemap *tilemap) { +void tilemap_background(struct tilemap *tilemap, int x, int y, int w, int h) { + SDL_SetRenderDrawColor(renderer, tilemap->backdrop.r, tilemap->backdrop.g, tilemap->backdrop.b, tilemap->backdrop.a); + SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, w, h}); + for (int i = 0; i < tilemap->middleground; i++) { + SDL_RenderCopy(renderer, tilemap->tilemaps[i], &(SDL_Rect) {x * tilemap->parallax[i].x, y * tilemap->parallax[i].y, w, h}, &(SDL_Rect) {0, 0, w, h}); + } +} + +void tilemap_foreground(struct tilemap *tilemap, int x, int y, int w, int h) { + for (int i = tilemap->middleground; i < tilemap->layers; i++) { + SDL_RenderCopy(renderer, tilemap->tilemaps[i], &(SDL_Rect) {x * tilemap->parallax[i].x, y * tilemap->parallax[i].y, w, h}, &(SDL_Rect) {0, 0, w, h}); + } +} + +void tilemap_free(struct tilemap *tilemap) { SDL_DestroyTexture(tilemap->tileset); SDL_DestroyTexture(tilemap->wang_tileset); free(tilemap->parallax); @@ -38,11 +59,23 @@ void free_tilemap(struct tilemap *tilemap) { free(tilemap); } -struct tilemap *load_tilemap(void *data, size_t size) { +struct tilemap *tilemap_load(void *data, size_t size) { + size_t const insize = size; + + struct sets *const sets = data; + data = sets + 1; + size -= sizeof (struct sets); + + if (memcmp(sets->magic, MAGIC, sizeof (MAGIC)) != 0) { + fprintf(stderr, "error: unsupported level format (got '%.4s' expected '%.4s')\n", sets->magic, MAGIC); + return NULL; + } + struct tilemap *tilemap = malloc(sizeof (struct tilemap)); if (tilemap == NULL) { return NULL; } + tilemap->tileset = SDL_CreateTexture(renderer, SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, 128, 128); tilemap->wang_tileset = SDL_CreateTexture(renderer, SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, 128, 128); SDL_SetTextureBlendMode(tilemap->wang_tileset, SDL_BLENDMODE_BLEND); @@ -51,9 +84,6 @@ struct tilemap *load_tilemap(void *data, size_t size) { tilemap->collision = NULL; tilemap->tilemaps = NULL; - struct sets *const sets = data; - data = sets + 1; - size -= sizeof (struct sets); char *str = data; int y = 0; SDL_SetRenderTarget(renderer, tilemap->tileset); @@ -95,7 +125,7 @@ struct tilemap *load_tilemap(void *data, size_t size) { str += sizeof (uint32_t); size_t len = strnlen(str, size); if (len == size) { - free_tilemap(tilemap); + tilemap_free(tilemap); return NULL; } void *tex = res_get_texture(str).data; @@ -117,11 +147,29 @@ struct tilemap *load_tilemap(void *data, size_t size) { goto fail; } + tilemap->backdrop.r = map->backdrop.r; + tilemap->backdrop.g = map->backdrop.g; + tilemap->backdrop.b = map->backdrop.b; + tilemap->backdrop.a = map->backdrop.a; tilemap->width = map->width; tilemap->height = map->height; tilemap->layers = map->layers; + tilemap->middleground = map->middleground; tilemap->tilemaps = malloc(sizeof (void *) * tilemap->layers); + if (tilemap->middleground > tilemap->layers) { + goto fail; + } else if (tilemap->middleground == 0) { + fputs("warn: map has no middle ground\n", stderr); + tilemap->collision = calloc(tilemap->width, tilemap->height * sizeof (collision_T)); + } else { + tilemap->collision = malloc(tilemap->width * tilemap->height * sizeof (collision_T)); + size_t const ll = (tilemap->middleground - 1) * map->width * map->height; + for (size_t i = 0; i < tilemap->width * tilemap->height; i++) { + tilemap->collision[i] = collision[map->tiles[i + ll]]; + } + } + for (int l = 0; l < tilemap->layers; l++) { SDL_Texture *layer = SDL_CreateTexture(renderer, SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, map->width * 8, map->height * 8); SDL_SetTextureBlendMode(layer, SDL_BLENDMODE_BLEND); @@ -170,11 +218,13 @@ struct tilemap *load_tilemap(void *data, size_t size) { size -= sizeof (struct parallax) * map->layers; + tilemap->input_bytes = insize - size; + //fprintf(stderr, "size: %zuB remaining: %zuB total: %zuB\n", tilemap->input_bytes, size, insize); SDL_SetRenderTarget(renderer, NULL); return tilemap; fail: - free_tilemap(tilemap); + tilemap_free(tilemap); SDL_SetRenderTarget(renderer, NULL); return NULL; } diff --git a/src/tilemap.h b/src/tilemap.h index 587bdf6..912b67f 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -4,17 +4,24 @@ extern struct tilemap { void *tileset; void *wang_tileset; + struct { + unsigned char r, g, b, a; + } backdrop; unsigned width; unsigned height; unsigned layers; - unsigned behind; + unsigned middleground; struct parallax { float x, y; } *parallax; collision_T *collision; void **tilemaps; + size_t input_bytes; } *tilemap, *next_tilemap; -void init_tilemap(void); -void free_tilemap(struct tilemap *tilemap); -struct tilemap *load_tilemap(void *data, size_t size); +// render the fore/back ground of the tilemap to `renderer` +void tilemap_background(struct tilemap *tilemap, int x, int y, int w, int h); +void tilemap_foreground(struct tilemap *tilemap, int x, int y, int w, int h); + +void tilemap_free(struct tilemap *tilemap); +struct tilemap *tilemap_load(void *data, size_t size); diff --git a/utl/json2map/main.c b/utl/json2map/main.c index f3e7716..b298626 100644 --- a/utl/json2map/main.c +++ b/utl/json2map/main.c @@ -12,15 +12,22 @@ struct tilemap_T { #define PACKED __attribute__((__packed__)) +#define MAGIC "TMv1" + struct PACKED sets { + uint8_t magic[4]; uint32_t tilesets_count; uint32_t wang_count; }; struct PACKED map { + struct { + uint8_t r, g, b, a; + } backdrop; uint32_t width; uint32_t height; uint32_t layers; + uint32_t middleground; uint8_t tiles[]; }; @@ -119,7 +126,7 @@ int main(int argc, char **argv) { uint32_t wang_height; char *tilesets_data = NULL; size_t tilesets_size = 0; - struct sets counts = {0, 0}; + struct sets counts = {MAGIC, 0, 0}; cJSON_ArrayForEach(tileset, tilesets) { //printf("=== tileset (%% tiles) ===\n"); @@ -217,12 +224,39 @@ int main(int argc, char **argv) { return 1; } struct map map = { + .backdrop = {0x9f, 0x9f, 0x9f, 0xff}, .width = width_obj->valueint - 1, .height = height_obj->valueint - 1, .layers = 0, + .middleground = 0, }; uint8_t *tile_data = NULL; float *parallaxes = NULL; + + cJSON const *backdrop = cJSON_GetObjectItemCaseSensitive(json, "backgroundcolor"); + if (cJSON_IsString(backdrop)) { + switch (strlen(backdrop->valuestring)) { + unsigned value; + case 9: + value = strtoul(backdrop->valuestring + 1, NULL, 16); + map.backdrop.r = value >> 16; + map.backdrop.g = value >> 8; + map.backdrop.b = value >> 0; + map.backdrop.a = value >> 24; + break; + case 7: + value = strtoul(backdrop->valuestring + 1, NULL, 16); + map.backdrop.r = value >> 16; + map.backdrop.g = value >> 8; + map.backdrop.b = value >> 0; + map.backdrop.a = 0xff; + break; + default: + fputs("incorrect backdrop color format\n", stderr); + return 1; + } + } + //printf("sky: # %02x %02x %02x %02x\n", map.backdrop.r, map.backdrop.g, map.backdrop.b, map.backdrop.a); cJSON const *layers = cJSON_GetObjectItemCaseSensitive(json, "layers"); cJSON const *layer = NULL; @@ -334,6 +368,20 @@ int main(int argc, char **argv) { } else { // ??? layer } + + cJSON const *properties = cJSON_GetObjectItemCaseSensitive(layer, "properties"); + cJSON const *property = NULL; + cJSON_ArrayForEach (property, properties) { + char const *const name = cJSON_GetObjectItemCaseSensitive(property, "name")->valuestring; + if (strcmp(name, "middleground") == 0) { + if (cJSON_IsTrue(cJSON_GetObjectItemCaseSensitive(property, "value"))) { + map.middleground = map.layers; + } + } else { + printf("unknown property '%s'\n", name); + return 1; + } + } } fwrite(&counts, 1, sizeof (counts), outfile); -- cgit 1.4.1-2-gfad0