From 5a63b4c2710732f73caed6fa9fa08fcf1ca7fd44 Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Sun, 17 Feb 2013 04:50:18 -0500 Subject: Support layers in maps. --- (limited to 'src') diff --git a/src/resources/map.c b/src/resources/map.c index ea2144f..7eda415 100644 --- a/src/resources/map.c +++ b/src/resources/map.c @@ -6,6 +6,8 @@ #include "map.h" #include "resource.h" #include "../xml.h" +#include "../base64.h" +#include "../compression.h" #include "../logging.h" struct resource_table ts_res; @@ -20,6 +22,10 @@ static void XMLCALL tmx_tileset_end(void *, const char *); static void XMLCALL tmx_tilesetemb_end(void *, const char *); static void XMLCALL tmx_tileset_el_start(void *, const char *, const char **); static void XMLCALL tmx_image_end(void *, const char *); +static void XMLCALL tmx_layer_el_start(void *, const char *, const char **); +static void XMLCALL tmx_layer_end(void *, const char *); +static void XMLCALL tmx_data_end(void *, const char *); +static void XMLCALL tmx_data_cdata(void *, const char *, int); static void XMLCALL tmx_unused_start(void *, const char *, const char **); static void XMLCALL tmx_unused_end(void *, const char *); static void XMLCALL tmx_invalid_start(void *, const char *, const char **); @@ -97,17 +103,6 @@ map_get(const char *path) } void -map_add_layer(struct map *m, struct layer *l) -{ - if (m->layers_head == NULL) { - m->layers_head = l; - } else { - m->layers_tail->next = l; - } - m->layers_tail = l; -} - -void map_add_tileset(struct map *m, struct tileset *t, int firstgid) { struct map_tileset *mts; @@ -129,6 +124,28 @@ map_add_tileset(struct map *m, struct tileset *t, int firstgid) m->tilesets_tail = mts; } +struct layer * +map_get_layer(struct map *m, const char *name) +{ + if (strcmp(name, "ground") == 0) { + return &m->layers[LAYER_GROUND]; + } else if (strcmp(name, "obj-low") == 0) { + return &m->layers[LAYER_OBJ_LOW]; + } else if (strcmp(name, "char-bot") == 0) { + return &m->layers[LAYER_CHAR_BOT]; + } else if (strcmp(name, "obj-mid") == 0) { + return &m->layers[LAYER_OBJ_MID]; + } else if (strcmp(name, "char-top") == 0) { + return &m->layers[LAYER_CHAR_TOP]; + } else if (strcmp(name, "obj-high") == 0) { + return &m->layers[LAYER_OBJ_HIGH]; + } else if (strcmp(name, "weather") == 0) { + return &m->layers[LAYER_WEATHER]; + } else { + return NULL; + } +} + static struct tileset * tileset_get(const char *path, const char *basedir) { @@ -243,14 +260,17 @@ tmx_map_el_start(void *pv, const char *name, const char **attr) char *source; char *path; struct tileset *ts; + char *ly_name; + struct layer *ly; debug("<%s> (map child)", name); + m = xml_node_peek(p); + if (xml_check_tag(name, "properties")) { /* Not used by engine. */ xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL); } else if (xml_check_tag(name, "tileset")) { - m = xml_node_peek(p); dirname = m->dirname; source = NULL; xml_get_string_attr(p, attr, "source", &source, 0); @@ -281,6 +301,13 @@ tmx_map_el_start(void *pv, const char *name, const char **attr) tmx_tilesetemb_end, NULL); } xml_get_int_attr(p, attr, "firstgid", &m->cur_ts_firstgid, 1); + } else if (xml_check_tag(name, "layer")) { + ly_name = NULL; + xml_get_string_attr(p, attr, "name", &ly_name, 1); + ly = map_get_layer(m, ly_name); + free(ly_name); + ly->map = m; + xml_node_push(p, ly, tmx_layer_el_start, tmx_layer_end, NULL); } else { xml_unexpected_start_tag(p, name, "properties, tileset, layer, or objectgroup"); @@ -293,7 +320,7 @@ tmx_tileset_start(void *pv, const char *name, const char **attr) XML_Parser p = (XML_Parser) pv; struct tileset *ts; - debug("<%s> (tileset)", name); + debug("<%s> (external tileset)", name); if (xml_check_tag(name, "tileset")) { ts = xml_node_peek(p); @@ -350,7 +377,10 @@ tmx_tileset_el_start(void *pv, const char *name, const char **attr) debug("<%s> (tileset child)", name); - if (xml_check_tag(name, "image")) { + if (xml_check_tag(name, "tileoffset")) { + /* Not used by engine. */ + xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL); + } else if (xml_check_tag(name, "image")) { dirname = ((struct tileset *) xml_node_peek(p))->dirname; xml_get_string_attr(p, attr, "source", &source, 0); path = malloc(strlen(dirname) + strlen(source) + 2); @@ -361,6 +391,11 @@ tmx_tileset_el_start(void *pv, const char *name, const char **attr) img = img_png_get(path); free(source); xml_node_push(p, img, tmx_invalid_start, tmx_image_end, NULL); +#if 0 + } else if (xml_check_tag(name, "tile")) { + xml_node_push(p, img, tmx_tile_properties_start, tmx_tile_end, + NULL); +#endif } else { xml_unexpected_start_tag(p, name, "image"); } @@ -385,6 +420,142 @@ tmx_image_end(void *pv, const char *name) } static void XMLCALL +tmx_layer_el_start(void *pv, const char *name, const char **attr) +{ + XML_Parser p = (XML_Parser) pv; + struct layer *ly; + + debug("<%s> (layer child)", name); + + ly = xml_node_peek(p); + + if (xml_check_tag(name, "properties")) { + /* Not used by engine. */ + xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL); + } else if (xml_check_tag(name, "data")) { + /* NB: This parser requires an encoding. The author is too lazy + * to parse a bunch of elements. */ + xml_get_string_attr(p, attr, "encoding", &ly->encoding, 1); + xml_get_string_attr(p, attr, "compression", &ly->compression, + 0); + xml_node_push(p, ly, tmx_invalid_start, tmx_data_end, + tmx_data_cdata); + } else { + xml_unexpected_start_tag(p, name, "layer"); + } +} + +static void XMLCALL +tmx_layer_end(void *pv, const char *name) +{ + XML_Parser p = (XML_Parser) pv; + + debug(" (layer)", name); + + if (xml_check_tag(name, "layer")) { + xml_node_pop(p); + } else { + xml_unexpected_end_tag(p, name, "layer"); + } +} + +static void XMLCALL +tmx_data_end(void *pv, const char *name) +{ + XML_Parser p = (XML_Parser) pv; + struct layer *ly; + size_t decoded_len; + size_t decomp_len; + char *decoded_buf; + char *decomp_buf; + + debug(" (data)", name); + + ly = xml_node_peek(p); + + if (xml_check_tag(name, "data")) { + decoded_len = strlen(ly->raw_data); + decomp_len = 4 * ly->map->width * ly->map->height; + debug("Expected map data size: %d", decomp_len); + decoded_buf = malloc(decoded_len + 1); + if (decoded_buf == NULL) { + warn("Failed to allocate layer data buffer"); + return; + } + if (strcmp(ly->encoding, "base64") == 0) { + debug("Decoding base 64 layer data..."); + base64_decode(ly->raw_data, + decoded_buf, decoded_len + 1); + } + if (ly->compression == NULL) { + debug("Layer data already decompressed"); + decomp_buf = decoded_buf; + } else if (strcmp(ly->compression, "zlib") == 0) { + debug("Decompressing layer data with zlib..."); + decomp_buf = malloc(decomp_len); + if (decomp_buf == NULL) { + warn("Failed to allocate layer data buffer"); + return; + } + decompress(decoded_buf, decoded_len, + decomp_buf, decomp_len); + free(decoded_buf); + } else if (strcmp(ly->compression, "gzip") == 0) { + debug("Decompressing layer data with gzip..."); + decomp_buf = malloc(decomp_len); + if (decomp_buf == NULL) { + warn("Failed to allocate layer data buffer"); + } + 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(ly->raw_data); + ly->tiles = (Uint32 *) decomp_buf; + xml_node_pop(p); + } else { + xml_unexpected_end_tag(p, name, "data"); + } +} + +static void XMLCALL +tmx_data_cdata(void *pv, const char *s, int len) +{ + XML_Parser p = (XML_Parser) pv; + struct layer *ly; + char *s_z; + char *s_z_trimmed, *s_z_trimmed_end; + + debug("[CDATA]"); + + ly = 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') { + 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'; + + ly->raw_data = strdup(s_z_trimmed); + + free(s_z); +} + +static void XMLCALL tmx_unused_start(void *pv, const char *name, const char **attr) { XML_Parser p = (XML_Parser) pv; @@ -403,7 +574,7 @@ tmx_unused_end(void *pv, const char *name) { XML_Parser p = (XML_Parser) pv; - debug("<%s> (unused)", name); + debug(" (unused)", name); /* Shut up, GCC. */ for (; *name != '\0'; ++name); diff --git a/src/resources/map.h b/src/resources/map.h index 2926aa5..11ba808 100644 --- a/src/resources/map.h +++ b/src/resources/map.h @@ -4,8 +4,17 @@ #include #include "resource.h" #include "image.h" -#include "layer.h" +enum layer_id { + LAYER_GROUND = 0, + LAYER_OBJ_LOW, + LAYER_CHAR_BOT, + LAYER_OBJ_MID, + LAYER_CHAR_TOP, + LAYER_OBJ_HIGH, + LAYER_WEATHER, + LAYERS_MAX +}; struct tileset { struct resource res; char *dirname; @@ -19,6 +28,13 @@ struct map_tileset { int firstgid; struct map_tileset *next; }; +struct layer { + struct map *map; + Uint32 *tiles; + char *encoding; + char *compression; + char *raw_data; +}; struct map { struct resource res; char *dirname; @@ -28,15 +44,14 @@ struct map { int tileheight; struct map_tileset *tilesets_head; struct map_tileset *tilesets_tail; - struct layer *layers_head; - struct layer *layers_tail; + struct layer layers[LAYERS_MAX]; Uint8 *collision; int cur_ts_firstgid; }; struct map *map_get(const char *path); void map_free(struct map *map); -void map_add_layer(struct map *m, struct layer *l); void map_add_tileset(struct map *m, struct tileset *t, int firstgid); +struct layer *map_get_layer(struct map *m, const char *name); #endif -- cgit v0.9.1