From 9942429dbb83fed5532c070f8afe41d6ddcd66d2 Mon Sep 17 00:00:00 2001 From: zlago Date: Wed, 25 Sep 2024 14:02:49 +0200 Subject: parallax --- utl/json2map/main.c | 356 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 utl/json2map/main.c (limited to 'utl/json2map/main.c') diff --git a/utl/json2map/main.c b/utl/json2map/main.c new file mode 100644 index 0000000..3bc7ba4 --- /dev/null +++ b/utl/json2map/main.c @@ -0,0 +1,356 @@ +#include +#include +#include +#include +#include "cJSON.h" +#include "common.h" + +struct tilemap_T { + unsigned width, height; + int *tilemap; +}; + +#define PACKED __attribute__((__packed__)) + +struct PACKED sets { + uint32_t tilesets_count; + uint32_t wang_count; +}; + +struct PACKED map { + uint32_t width; + uint32_t height; + uint32_t layers; + uint8_t tiles[]; +}; + +struct tilemap_T make_tilemap(cJSON const *const layer, int const wangStart, int const wangSize) { + cJSON const *width_obj = cJSON_GetObjectItemCaseSensitive(layer, "width"); + cJSON const *height_obj = cJSON_GetObjectItemCaseSensitive(layer, "height"); + if (!cJSON_IsNumber(width_obj) || !cJSON_IsNumber(height_obj)) { + fputs("missing tile layer size\n", stderr); + return (struct tilemap_T) {0, 0, NULL}; + } + int const width = width_obj->valueint; + int const height = height_obj->valueint; + cJSON const *data = cJSON_GetObjectItemCaseSensitive(layer, "data"); + int const size = cJSON_GetArraySize(data); + if (width * height != size) { + fputs("tile data size mismatch", stderr); + return (struct tilemap_T) {0, 0, NULL}; + } + struct tilemap_T in = {.tilemap = NULL, .width = width, .height = height}; + in.tilemap = malloc(size * sizeof (int)); + cJSON const *tile = NULL; + size_t i = 0; + cJSON_ArrayForEach (tile, data) { + in.tilemap[i] = tile->valueint; + i++; + } + struct tilemap_T out = {.tilemap = NULL, .width = width - 1, .height = height - 1}; + out.tilemap = malloc(out.width * out.height * sizeof (int)); + printf("=== tilemap (%d tiles) ===\n", size); + for (int y = 0; y < out.height; y++) { + for (int x = 0; x < out.width; x++) { + int a = in.tilemap[x + y * in.width]; + if (a == 0) { + out.tilemap[x + y * out.width] = 0; + } else if (a < wangStart) { + out.tilemap[x + y * out.width] = a - 1; + } else if (a > wangStart + wangSize) { + out.tilemap[x + y * out.width] = a - wangSize - 1; + } else { + int b = (in.tilemap[x + y * in.width] - wangStart) >> 4; + int c = (in.tilemap[(x + 1) + y * in.width] - wangStart) >> 4; + int d = (in.tilemap[x + (y + 1) * in.width] - wangStart) >> 4; + int e = (in.tilemap[(x + 1) + (y + 1) * in.width] - wangStart) >> 4; + int f = b == c && b == d && b == e; + if (f) { + out.tilemap[x + y * out.width] = b + 0xf0; + } else { + out.tilemap[x + y * out.width] = 0; + } + } + } + } + free(in.tilemap); + return out; +} + +size_t safe_write(void const *restrict buf, size_t size, FILE *restrict stream) { + if (stream == NULL) { + return 0; + } + return fwrite(buf, 1, size, stream); +} + +int main(int argc, char **argv) { + if (argc != 2 && argc != 3) { + return EXIT_FAILURE; + } + struct blob file = load_file(argv[1]); + cJSON *json = cJSON_ParseWithLength(file.data, file.size); + free(file.data); + + FILE *outfile = NULL; + if (argc == 3) { + outfile = fopen(argv[2], "wb"); + } + + int status = EXIT_SUCCESS; + if (json == NULL) { + puts("null"); + status = EXIT_FAILURE; + goto end; + } + cJSON const *tilewidth = cJSON_GetObjectItemCaseSensitive(json, "tilewidth"); + cJSON const *tileheight = cJSON_GetObjectItemCaseSensitive(json, "tileheight"); + if (!cJSON_IsNumber(tilewidth) || !cJSON_IsNumber(tileheight) || tilewidth->valueint != 8 || tileheight->valueint != 8) { + status = EXIT_FAILURE; + goto end; + } + + cJSON const *tilesets = cJSON_GetObjectItemCaseSensitive(json, "tilesets"); + cJSON const *tileset = NULL; + int wangStart = 0; + int wangSize = 0; + + char *wang_tileset = NULL; + uint32_t wang_height; + char *tilesets_data = NULL; + size_t tilesets_size = 0; + struct sets counts = {0, 0}; + + cJSON_ArrayForEach(tileset, tilesets) { + printf("=== tileset (%% tiles) ===\n"); + cJSON const *wangs = cJSON_GetObjectItemCaseSensitive(tileset, "wangsets"); + if (wangs != NULL) { + cJSON const *wang = NULL; + cJSON_ArrayForEach(wang, wangs) { + puts("=== wang ==="); + cJSON const *type = cJSON_GetObjectItemCaseSensitive(wang, "type"); + if (strcmp("corner", type->valuestring) == 0) { + if (wangStart != 0) { + fputs("two or more corner sets\n", stderr); + status = EXIT_FAILURE; + goto end; + } + wangStart = cJSON_GetObjectItemCaseSensitive(tileset, "firstgid")->valueint; + wangSize = cJSON_GetObjectItemCaseSensitive(tileset, "tilecount")->valueint; + wang_tileset = cJSON_GetObjectItemCaseSensitive(tileset, "image")->valuestring; + switch (cJSON_GetObjectItemCaseSensitive(tileset, "imagewidth")->valueint) { + case 32: + wang_height = cJSON_GetObjectItemCaseSensitive(tileset, "imageheight")->valueint / 4; + break; + case 128: + wang_height = cJSON_GetObjectItemCaseSensitive(tileset, "imageheight")->valueint; + break; + default: + goto end; + } + printf("=== wang %u-%u ===\n", wangStart, wangStart + wangSize); + counts.wang_count++; + goto wang_continue; + } + } + } + cJSON const *image = cJSON_GetObjectItemCaseSensitive(tileset, "image"); + { + char const *const str = image->valuestring; + size_t start = 0, length = strlen(str); + for (size_t i = 0; i < length; i++) { + if (str[i] == '/') { + start = i + 1; + } + } + length -= start; + for (size_t i = length; i > 0; i--) { + if (str[start + i] == '.') { + length = i; + break; + } + } + //printf("%.*s\n", (int) length, str + start); + uint32_t height = cJSON_GetObjectItemCaseSensitive(tileset, "imageheight")->valueint; + tilesets_data = realloc(tilesets_data, tilesets_size + length + sizeof (uint32_t) + 1); + memcpy(tilesets_data + tilesets_size, &height, sizeof (uint32_t)); + memcpy(tilesets_data + tilesets_size + sizeof (uint32_t), str + start, length); + tilesets_data[tilesets_size + sizeof (uint32_t) + length] = 0; + puts(tilesets_data + tilesets_size + sizeof (uint32_t)); + tilesets_size += length + sizeof (uint32_t) + 1; + counts.tilesets_count++; + } + puts(image->valuestring); + #if 0 + char *str = cJSON_Print(tileset); + puts(str); + free(str); + #endif + wang_continue:; + } + if (counts.wang_count == 1) { + char const *const str = wang_tileset; + size_t start = 0, length = strlen(str); + for (size_t i = 0; i < length; i++) { + if (str[i] == '/') { + start = i + 1; + } + } + length -= start; + for (size_t i = length; i > 0; i--) { + if (str[start + i] == '.') { + length = i; + break; + } + } + //printf("%.*s\n", (int) length, str + start); + wang_tileset = malloc(length + 1); + memcpy(wang_tileset, str + start, length); + wang_tileset[length] = 0; + puts(wang_tileset); + } + + cJSON const *width_obj = cJSON_GetObjectItemCaseSensitive(json, "width"); + cJSON const *height_obj = cJSON_GetObjectItemCaseSensitive(json, "height"); + if (!cJSON_IsNumber(width_obj) || !cJSON_IsNumber(height_obj)) { + fputs("missing tilemap size\n", stderr); + return 1; + } + struct map map = { + .width = width_obj->valueint - 1, + .height = height_obj->valueint - 1, + .layers = 0, + }; + uint8_t *tile_data = NULL; + float *parallaxes = NULL; + + cJSON const *layers = cJSON_GetObjectItemCaseSensitive(json, "layers"); + cJSON const *layer = NULL; + cJSON_ArrayForEach (layer, layers) { + cJSON const *type_obj = cJSON_GetObjectItemCaseSensitive(layer, "type"); + if (!cJSON_IsString(type_obj)) { + status = EXIT_FAILURE; + goto end; + } + char const *type = type_obj->valuestring; + puts(type); + if (strcmp(type, "group") == 0) { + // group layer + cJSON const *sublayers = cJSON_GetObjectItemCaseSensitive(layer, "layers"); + cJSON const *sublayer = NULL; + struct tilemap_T layert = {.tilemap = NULL, .width = 0, .height = 0}; + cJSON_ArrayForEach (sublayer, sublayers) { + struct tilemap_T tilemap = make_tilemap(sublayer, wangStart, wangSize); + if (tilemap.tilemap == NULL) { + status = EXIT_FAILURE; + goto end; + } + if (layert.tilemap == NULL) { + layert.width = tilemap.width; + layert.height = tilemap.height; + layert.tilemap = malloc(layert.width * layert.height * sizeof (int)); + memcpy(layert.tilemap, tilemap.tilemap, layert.width * layert.height * sizeof (int)); + } else { + for (size_t i = 0; i < layert.width * layert.height; i++) { + if (tilemap.tilemap[i] != 0) { + layert.tilemap[i] = tilemap.tilemap[i]; + } + } + } + free(tilemap.tilemap); + } + for (int y = 0; y < layert.height; y++) { + for (int x = 0; x < layert.width; x++) { + printf("%2x,", layert.tilemap[x + y * layert.width]); + } + fputc('\n', stdout); + } + + size_t const layer_size = map.width * map.height; + tile_data = realloc(tile_data, layer_size * (map.layers + 1)); + for (size_t i = 0; i < layer_size; i++) { + tile_data[layer_size * map.layers + i] = layert.tilemap[i]; + } + + parallaxes = realloc(parallaxes, sizeof (float) * 2 * (map.layers + 1)); + float px = 1.0f, py = 1.0f; + cJSON const *parallax; + parallax = cJSON_GetObjectItemCaseSensitive(layer, "parallaxx"); + if (cJSON_IsNumber(parallax)) { + px = parallax->valuedouble; + } + parallax = cJSON_GetObjectItemCaseSensitive(layer, "parallaxy"); + if (cJSON_IsNumber(parallax)) { + py = parallax->valuedouble; + } + printf("parallax: %fx%f\n", px, py); + parallaxes[map.layers * 2 + 0] = px; + parallaxes[map.layers * 2 + 1] = py; + + map.layers++; + free(layert.tilemap); + } else if (strcmp(type, "tilelayer") == 0) { + // tile layer + struct tilemap_T tilemap = make_tilemap(layer, wangStart, wangSize); + if (tilemap.tilemap == NULL) { + status = EXIT_FAILURE; + goto end; + } + for (int y = 0; y < tilemap.height; y++) { + for (int x = 0; x < tilemap.width; x++) { + printf("%2x,", tilemap.tilemap[x + y * tilemap.width]); + } + fputc('\n', stdout); + } + + size_t const layer_size = map.width * map.height; + tile_data = realloc(tile_data, layer_size * (map.layers + 1)); + for (size_t i = 0; i < layer_size; i++) { + tile_data[layer_size * map.layers + i] = tilemap.tilemap[i]; + } + + parallaxes = realloc(parallaxes, sizeof (float) * 2 * (map.layers + 1)); + float px = 1.0f, py = 1.0f; + cJSON const *parallax; + parallax = cJSON_GetObjectItemCaseSensitive(layer, "parallaxx"); + if (cJSON_IsNumber(parallax)) { + px = parallax->valuedouble; + } + parallax = cJSON_GetObjectItemCaseSensitive(layer, "parallaxy"); + if (cJSON_IsNumber(parallax)) { + py = parallax->valuedouble; + } + printf("parallax: %fx%f\n", px, py); + parallaxes[map.layers * 2 + 0] = px; + parallaxes[map.layers * 2 + 1] = py; + + map.layers++; + free(tilemap.tilemap); + #if 0 + char *str = cJSON_Print(layer); + puts(str); + free(str); + #endif + } else { + // ??? layer + } + } + + fwrite(&counts, 1, sizeof (counts), outfile); + fwrite(tilesets_data, 1, tilesets_size, outfile); + if (wang_tileset != NULL) { + fwrite(&wang_height, 1, sizeof (uint32_t), outfile); + fwrite(wang_tileset, 1, strlen(wang_tileset) + 1, outfile); + } + fwrite(&map, 1, sizeof (map), outfile); + fwrite(tile_data, 1, map.width * map.height * map.layers, outfile); + fwrite(parallaxes, 1, sizeof (float) * 2 * map.layers, outfile); + + free(tile_data); + end: + if (outfile != NULL) { + fclose(outfile); + } + cJSON_Delete(json); + return status; +} -- cgit 1.4.1-2-gfad0