summaryrefslogtreecommitdiff
path: root/utl/json2map/main.c
diff options
context:
space:
mode:
authorzlago2024-09-25 14:02:49 +0200
committerzlago2024-09-25 14:19:32 +0200
commit9942429dbb83fed5532c070f8afe41d6ddcd66d2 (patch)
tree70f7d3872de143a7f256b3913e2bf52724d23c3a /utl/json2map/main.c
parentb23a3ab831f91553d34a48f51370ed9525de07ac (diff)
parallax
Diffstat (limited to 'utl/json2map/main.c')
-rw-r--r--utl/json2map/main.c356
1 files changed, 356 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#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;
+}