summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorP. J. McDermott <pjm@nac.net>2013-02-17 04:50:18 (EST)
committer P. J. McDermott <pjm@nac.net>2013-02-17 04:50:18 (EST)
commit5a63b4c2710732f73caed6fa9fa08fcf1ca7fd44 (patch)
tree9f0690d206c1973296c9b65c31e24d7a6fc492ce /src
parent3c09671866ff5131bcbb044b0df6326ff891fee6 (diff)
downloadoverworld-rpg-5a63b4c2710732f73caed6fa9fa08fcf1ca7fd44.zip
overworld-rpg-5a63b4c2710732f73caed6fa9fa08fcf1ca7fd44.tar.gz
overworld-rpg-5a63b4c2710732f73caed6fa9fa08fcf1ca7fd44.tar.bz2
Support layers in maps.
Diffstat (limited to 'src')
-rw-r--r--src/resources/map.c201
-rw-r--r--src/resources/map.h23
2 files changed, 205 insertions, 19 deletions
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 <tile> 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("</%s> (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("</%s> (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("</%s> (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 <SDL_stdinc.h>
#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