summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorP. J. McDermott <pj@pehjota.net>2021-03-23 16:49:20 (EDT)
committer P. J. McDermott <pj@pehjota.net>2021-03-23 16:49:20 (EDT)
commit6a7786f86faf22b7e0a2c844126ec99d7c622d24 (patch)
treee2c60e7d8b2cc0344eb1d04d974a7d7df536df66
parent18946b0027be597fb9fa4d4d5e5814a5b6b98b6d (diff)
downloaddodge-balls-6a7786f86faf22b7e0a2c844126ec99d7c622d24.zip
dodge-balls-6a7786f86faf22b7e0a2c844126ec99d7c622d24.tar.gz
dodge-balls-6a7786f86faf22b7e0a2c844126ec99d7c622d24.tar.bz2
map: Parse layer data
-rw-r--r--src/map.c195
1 files changed, 181 insertions, 14 deletions
diff --git a/src/map.c b/src/map.c
index 3e7c0e3..314ae92 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 P. J. McDermott
+ * Copyright (C) 2013, 2021 P. J. McDermott
*
* This file is part of Dodge Balls
*
@@ -21,6 +21,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "base64.h"
+#include "compression.h"
#include "defs.h"
#include "dirs.h"
#include "map.h"
@@ -28,18 +30,28 @@
#include "output.h"
#include "xml.h"
+struct db_map_layer {
+ Uint32 *tiles;
+ char *encoding;
+ char *compression;
+ char *raw_data;
+ struct db_map_layer *next;
+};
+
struct db_map {
- char *game_id;
- int w;
- int h;
- int tw;
- int th;
- Uint8 bg_r;
- Uint8 bg_g;
- Uint8 bg_b;
- int fr;
- struct db_tileset *tileset_head;
- struct db_tileset *tileset_tail;
+ char *game_id;
+ int w;
+ int h;
+ int tw;
+ int th;
+ Uint8 bg_r;
+ Uint8 bg_g;
+ Uint8 bg_b;
+ int fr;
+ struct db_tileset *tileset_head;
+ struct db_tileset *tileset_tail;
+ struct db_map_layer *layer_head;
+ struct db_map_layer *layer_tail;
};
static char *
@@ -175,6 +187,162 @@ _db_tmx_tileset_end(void *pv, const char *name)
}
static void XMLCALL
+_db_tmx_cdata(void *pv, const char *s, int len)
+{
+ XML_Parser p;
+ struct db_map *map;
+ char *s_z;
+ char *s_z_trimmed;
+ char *s_z_trimmed_end;
+ char *old_data;
+
+ p = (XML_Parser) pv;
+ map = db_xml_node_peek(p);
+
+ s_z = s_z_trimmed = strndup(s, len);
+
+ while(isspace(*s_z_trimmed)) {
+ ++s_z_trimmed;
+ --len;
+ }
+ if (*s_z_trimmed == '\0') {
+ db_dbg(" (null)");
+ free(s_z);
+ return;
+ }
+ s_z_trimmed_end = s_z_trimmed + len - 1;
+ while (s_z_trimmed_end > s_z_trimmed && isspace(*s_z_trimmed_end)) {
+ --s_z_trimmed_end;
+ }
+ *(s_z_trimmed_end + 1) = '\0';
+
+ db_dbg(" %s", s_z_trimmed);
+ if (map->layer_tail->raw_data != NULL &&
+ *map->layer_tail->raw_data != '\0') {
+ old_data = map->layer_tail->raw_data;
+ sprintf(map->layer_tail->raw_data, "%s %s",
+ map->layer_tail->raw_data, strdup(s_z_trimmed));
+ free(old_data);
+ } else {
+ map->layer_tail->raw_data = strdup(s_z_trimmed);
+ }
+
+ free(s_z);
+}
+
+static void XMLCALL
+_db_tmx_data_end(void *pv, const char *name)
+{
+ XML_Parser p;
+ struct db_map *map;
+ size_t decoded_len;
+ size_t decomp_len;
+ char *decoded_buf;
+ char *decomp_buf;
+ size_t i;
+
+ db_dbg(" </%s> (data)", name);
+
+ p = (XML_Parser) pv;
+ map = db_xml_node_peek(p);
+
+ if (db_xml_check_tag(name, "data")) {
+ decoded_len = strlen(map->layer_tail->raw_data);
+ decomp_len = 4 * map->w* map->h;
+ db_dbg(" Expected map data size: %zu", decomp_len);
+ decoded_buf = malloc(decoded_len + 1);
+ if (decoded_buf == NULL) {
+ db_warn(" Failed to allocate layer data buffer");
+ XML_StopParser(p, XML_FALSE);
+ return;
+ }
+ if (strcmp(map->layer_tail->encoding, "base64") == 0) {
+ db_dbg(" Decoding base 64 layer data...");
+ db_base64_decode(map->layer_tail->raw_data,
+ decoded_buf, decoded_len + 1);
+ }
+ if (map->layer_tail->compression == NULL) {
+ db_dbg(" Layer data already decompressed");
+ decomp_buf = decoded_buf;
+ } else if (strcmp(map->layer_tail->compression, "zlib") == 0) {
+ db_dbg(" Decompressing layer data with zlib...");
+ decomp_buf = malloc(decomp_len);
+ if (decomp_buf == NULL) {
+ db_err("Failed to allocate layer data buffer");
+ free(decoded_buf);
+ XML_StopParser(p, XML_FALSE);
+ return;
+ }
+ db_decompress(decoded_buf, decoded_len,
+ decomp_buf, decomp_len);
+ free(decoded_buf);
+ } else if (strcmp(map->layer_tail->compression, "gzip") == 0) {
+ db_dbg(" Decompressing layer data with gzip...");
+ decomp_buf = malloc(decomp_len);
+ if (decomp_buf == NULL) {
+ db_err("Failed to allocate layer data buffer");
+ free(decoded_buf);
+ XML_StopParser(p, XML_FALSE);
+ return;
+ }
+ db_decompress(decoded_buf, decoded_len,
+ decomp_buf, decomp_len);
+ free(decoded_buf);
+ } else {
+ /* This should never happen. This branch exists only to
+ * silence GCC's maybe-uninitialized warning on
+ * decomp_buf below. */
+ return;
+ }
+ free(map->layer_tail->raw_data);
+ map->layer_tail->tiles = malloc(decomp_len);
+ for (i = 0; i < decomp_len / 4; ++i) {
+ /* Convert each tile GID to the system's byte order. */
+ map->layer_tail->tiles[i] =
+ (decomp_buf[i * 4 + 0] & 0xFF << 000) |
+ (decomp_buf[i * 4 + 1] & 0xFF << 010) |
+ (decomp_buf[i * 4 + 2] & 0xFF << 020) |
+ (decomp_buf[i * 4 + 3] & 0xFF << 030);
+ }
+ free(decomp_buf);
+ db_xml_node_pop(p);
+ } else {
+ db_xml_unexpected_end_tag(p, name, "data");
+ }
+}
+
+static void XMLCALL
+_db_tmx_data_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p;
+ struct db_map *map;
+
+ db_dbg(" <%s> (data)", name);
+
+ p = (XML_Parser) pv;
+ map = db_xml_node_peek(p);
+
+ if (db_xml_check_tag(name, "data")) {
+ map->layer_tail = calloc(1, sizeof(*map->layer_tail));
+ if (map->layer_tail == NULL) {
+ XML_StopParser(p, XML_FALSE);
+ return;
+ }
+ if (map->layer_head == NULL) {
+ map->layer_head = map->layer_tail;
+ }
+ db_xml_get_string_attr(p, attr, "encoding",
+ &map->layer_tail->encoding, 1);
+ db_xml_get_string_attr(p, attr, "compression",
+ &map->layer_tail->compression, 0);
+ db_xml_node_push(p, map, _db_tmx_invalid_start,
+ _db_tmx_data_end, _db_tmx_cdata);
+ } else {
+ db_xml_unexpected_start_tag(p, name, "data");
+ }
+}
+
+static void XMLCALL
_db_tmx_layer_end(void *pv, const char *name)
{
XML_Parser p;
@@ -239,8 +407,7 @@ _db_tmx_map_el_start(void *pv, const char *name, const char **attr)
db_xml_node_push(p, map, _db_tmx_invalid_start,
_db_tmx_tileset_end, NULL);
} else if (db_xml_check_tag(name, "layer")) {
- /* TODO: data */
- db_xml_node_push(p, map, _db_tmx_invalid_start,
+ db_xml_node_push(p, map, _db_tmx_data_start,
_db_tmx_layer_end, NULL);
} else if (db_xml_check_tag(name, "objectgroup")) {
/* TODO: object */