summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorP. J. McDermott <pjm@nac.net>2013-11-18 03:13:38 (EST)
committer P. J. McDermott <pjm@nac.net>2013-11-18 03:13:38 (EST)
commit4c07bd8b98a3ac0dd9422a36f63c109b28d28ab5 (patch)
treeb8f465df57f009f0383e32e414b9dd3d703f22bb
parent7ec94ed7c6803ae75d73e2a9ec7e54eaa2a97379 (diff)
downloadoverworld-rpg-4c07bd8b98a3ac0dd9422a36f63c109b28d28ab5.zip
overworld-rpg-4c07bd8b98a3ac0dd9422a36f63c109b28d28ab5.tar.gz
overworld-rpg-4c07bd8b98a3ac0dd9422a36f63c109b28d28ab5.tar.bz2
Split up src/resources/map.c.
src/resources/map.c defines map parsing functions. src/resources/tileset.c defines tileset (internal or external) parsing functions. src/resources/tmx.c defines common parsing functions. Also, tileset_get() is now non-static.
-rw-r--r--src/resources/local.mk6
-rw-r--r--src/resources/map.c346
-rw-r--r--src/resources/map.h18
-rw-r--r--src/resources/tileset.c308
-rw-r--r--src/resources/tileset.h48
-rw-r--r--src/resources/tmx.c81
-rw-r--r--src/resources/tmx.h29
7 files changed, 474 insertions, 362 deletions
diff --git a/src/resources/local.mk b/src/resources/local.mk
index dcb9824..9f68f21 100644
--- a/src/resources/local.mk
+++ b/src/resources/local.mk
@@ -6,4 +6,8 @@ sdlex_SOURCES += \
src/resources/palette.c \
src/resources/palette.h \
src/resources/resource.c \
- src/resources/resource.h
+ src/resources/resource.h \
+ src/resources/tileset.c \
+ src/resources/tileset.h \
+ src/resources/tmx.c \
+ src/resources/tmx.h
diff --git a/src/resources/map.c b/src/resources/map.c
index a4a07f7..e190282 100644
--- a/src/resources/map.c
+++ b/src/resources/map.c
@@ -25,29 +25,20 @@
#include <config.h>
#include "map.h"
#include "resource.h"
+#include "tmx.h"
+#include "tileset.h"
#include "../xml.h"
#include "../base64.h"
#include "../compression.h"
#include "../logging.h"
-struct resource_table ts_res;
struct resource_table map_res;
-static struct tileset *tileset_get(const char *, const char *);
static void XMLCALL tmx_map_start(void *, const char *, const char **);
static void XMLCALL tmx_map_end(void *, const char *);
static void XMLCALL tmx_map_el_start(void *, const char *, const char **);
static void XMLCALL tmx_map_property_start(void *, const char *, const char **);
-static void XMLCALL tmx_tileset_start(void *, const char *, const char **);
-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_tile_end(void *, const char *);
-static void XMLCALL tmx_tile_properties_start(void *, const char *,
- const char **);
-static void XMLCALL tmx_tile_property_start(void *, const char *,
- 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 *);
@@ -63,10 +54,6 @@ static void XMLCALL tmx_object_spawn_el_start(void *, const char *,
static void XMLCALL tmx_object_spawn_end(void *, const char *);
static void XMLCALL tmx_object_exit_property_start(void *, const char *,
const char **);
-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 **);
-static void XMLCALL tmx_invalid_end(void *, const char *);
struct map *
map_get(const char *path)
@@ -218,77 +205,6 @@ map_add_exit(struct map *m, struct map_exit *e)
}
}
-static struct tileset *
-tileset_get(const char *path, const char *basedir)
-{
- struct tileset *ts;
- XML_Parser p;
- FILE *tmx_fp;
- void *tmx_buf;
- size_t len;
- enum XML_Status status;
-
- ts = (struct tileset *) resource_get(&ts_res, path);
- if (ts != NULL) {
- resource_use((struct resource *) ts);
- return ts;
- }
-
- ts = resource_alloc(path, sizeof(*ts));
- if (ts == NULL) {
- return NULL;
- }
- ts->dirname = strdup(basedir);
-
- p = XML_ParserCreate(NULL);
- if (p == NULL) {
- warn("Failed to create TSX parser");
- return NULL;
- }
-
- XML_UseParserAsHandlerArg(p);
- xml_node_push(p, ts, tmx_tileset_start, tmx_invalid_end, NULL);
-
- tmx_fp = fopen(path, "rb");
- if (tmx_fp == NULL) {
- warn("Failed to open TSX file");
- xml_node_pop(p);
- XML_ParserFree(p);
- return NULL;
- }
-
- tmx_buf = XML_GetBuffer(p, 8192);
- if (tmx_buf == NULL) {
- warn("Failed to create TSX parse buffer");
- xml_node_pop(p);
- XML_ParserFree(p);
- fclose(tmx_fp);
- return NULL;
- }
-
- while (!feof(tmx_fp)) {
- len = fread(tmx_buf, 1, 8192, tmx_fp);
- status = XML_ParseBuffer(p, len, feof(tmx_fp));
- if (status == XML_STATUS_OK) {
- continue;
- }
- warn("Failed to parse TSX file (%s)",
- XML_ErrorString(XML_GetErrorCode(p)));
- xml_node_pop(p);
- XML_ParserFree(p);
- fclose(tmx_fp);
- return NULL;
- }
-
- XML_ParserFree(p);
- fclose(tmx_fp);
-
- resource_use((struct resource *) ts);
- resource_add(&ts_res, path, (struct resource *) ts);
-
- return ts;
-}
-
static void XMLCALL
tmx_map_start(void *pv, const char *name, const char **attr)
{
@@ -482,49 +398,6 @@ tmx_map_property_start(void *pv, const char *name, const char **attr)
}
static void XMLCALL
-tmx_tileset_start(void *pv, const char *name, const char **attr)
-{
- XML_Parser p = (XML_Parser) pv;
- struct tileset *ts;
-
-#ifdef DEBUG_TMX
- debug("<%s> (external tileset)", name);
-#endif
-
- if (xml_check_tag(name, "tileset")) {
- ts = xml_node_peek(p);
- xml_get_string_attr(p, attr, "name", &ts->name, 1);
- xml_get_int_attr(p, attr, "tilewidth", &ts->tilewidth, 1);
- xml_get_int_attr(p, attr, "tileheight", &ts->tileheight, 1);
- if (strcmp(ts->name, "collision") == 0) {
- ts->type = TILESET_TYPE_COLLISION;
- } else {
- ts->type = TILESET_TYPE_IMAGE;
- }
- xml_node_push(p, ts, tmx_tileset_el_start, tmx_tileset_end,
- NULL);
- } else {
- xml_unexpected_start_tag(p, name, "tileset");
- }
-}
-
-static void XMLCALL
-tmx_tileset_end(void *pv, const char *name)
-{
- XML_Parser p = (XML_Parser) pv;
-
-#ifdef DEBUG_TMX
- debug("</%s> (external tileset)", name);
-#endif
-
- if (xml_check_tag(name, "tileset")) {
- xml_node_pop(p);
- } else {
- xml_unexpected_end_tag(p, name, "tileset");
- }
-}
-
-static void XMLCALL
tmx_tilesetemb_end(void *pv, const char *name)
{
XML_Parser p = (XML_Parser) pv;
@@ -545,163 +418,6 @@ tmx_tilesetemb_end(void *pv, const char *name)
}
static void XMLCALL
-tmx_tileset_el_start(void *pv, const char *name, const char **attr)
-{
- XML_Parser p = (XML_Parser) pv;
- struct tileset *ts;
- char *dirname;
- char *source;
- char *path;
- struct image *img;
-
-#ifdef DEBUG_TMX
- debug("<%s> (tileset child)", name);
-#endif
-
- ts = xml_node_peek(p);
-
- 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, "properties")) {
- /* Not used by engine. */
- xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL);
- } else if (xml_check_tag(name, "image")) {
- xml_get_int_attr(p, attr, "width", &ts->width, 1);
- xml_get_int_attr(p, attr, "height", &ts->height, 1);
- ts->width /= ts->tilewidth;
- ts->height /= ts->tileheight;
- img = NULL;
- if (ts->type == TILESET_TYPE_IMAGE) {
- dirname = ts->dirname;
- xml_get_string_attr(p, attr, "source", &source, 0);
- path = malloc(strlen(dirname) + strlen(source) + 2);
- if (path == NULL) {
- return;
- }
- sprintf(path, "%s/%s", dirname, source);
- img = img_png_get(path);
- /* TODO: Get the color key from the trans attribute. */
- SDL_SetColorKey(img->image, SDL_SRCCOLORKEY,
- SDL_MapRGB(img->image->format,
- 0xFC, 0x00, 0xFF));
- free(source);
- } else if (ts->type == TILESET_TYPE_COLLISION) {
- ts->collision_tiles = malloc(ts->width * ts->height *
- sizeof(*ts->collision_tiles));
- if (ts->collision_tiles == NULL) {
- return;
- }
- }
- xml_node_push(p, img, tmx_invalid_start, tmx_image_end, NULL);
- } else if (xml_check_tag(name, "tile")) {
- xml_get_int_attr(p, attr, "id", &ts->cur_collision_tile, 1);
- xml_node_push(p, ts, tmx_tile_properties_start, tmx_tile_end,
- NULL);
- } else {
- xml_unexpected_start_tag(p, name, "tileoffset, image, tile");
- }
-}
-
-static void XMLCALL
-tmx_image_end(void *pv, const char *name)
-{
- XML_Parser p = (XML_Parser) pv;
- struct image *img;
- struct tileset *ts;
-
-#ifdef DEBUG_TMX
- debug("</%s> (image)", name);
-#endif
-
- if (xml_check_tag(name, "image")) {
- img = (struct image *) xml_node_pop(p);
- ts = (struct tileset *) xml_node_peek(p);
- ts->image = img;
- } else {
- xml_unexpected_end_tag(p, name, "image");
- }
-}
-
-static void XMLCALL
-tmx_tile_end(void *pv, const char *name)
-{
- XML_Parser p = (XML_Parser) pv;
-
-#ifdef DEBUG_TMX
- debug("</%s> (tile)", name);
-#endif
-
- xml_node_pop(p);
-
- if (xml_check_tag(name, "tile")) {
- } else {
- xml_unexpected_end_tag(p, name, "tile");
- }
-}
-
-static void XMLCALL
-tmx_tile_properties_start(void *pv, const char *name, const char **attr)
-{
- XML_Parser p = (XML_Parser) pv;
- struct tileset *ts;
-
-#ifdef DEBUG_TMX
- debug("<%s> (tile properties)", name);
-#endif
-
- ts = xml_node_peek(p);
-
- if (xml_check_tag(name, "properties")) {
- /* <properties> has no attributes, but GCC warns of an
- * "unused parameter ‘attr’". */
- for (; 0; ++attr);
- xml_node_push(p, ts, tmx_tile_property_start, tmx_unused_end,
- NULL);
- } else {
- xml_unexpected_start_tag(p, name, "properties");
- }
-}
-
-static void XMLCALL
-tmx_tile_property_start(void *pv, const char *name, const char **attr)
-{
- XML_Parser p = (XML_Parser) pv;
- struct tileset *ts;
- char *attr_name;
- char *attr_value;
- int coll_t, coll_r, coll_b, coll_l;
- int n;
-
-#ifdef DEBUG_TMX
- debug("<%s> (tile property)", name);
-#endif
-
- ts = xml_node_peek(p);
-
- if (xml_check_tag(name, "property")) {
- xml_get_string_attr(p, attr, "name", &attr_name, 1);
- xml_get_string_attr(p, attr, "value", &attr_value, 1);
- if (strcmp(attr_name, "collision") ==0) {
- n = sscanf(attr_value, "%d,%d,%d,%d",
- &coll_t, &coll_r, &coll_b, &coll_l);
- if (n != 4) {
- return;
- }
- ts->collision_tiles[ts->cur_collision_tile] =
- coll_t << 3 | coll_r << 2 |
- coll_b << 1 | coll_l << 0;
- }
- free(attr_name);
- free(attr_value);
- for (; 0; ++attr, ++ts);
- xml_node_push(p, NULL, tmx_invalid_start, tmx_unused_end, NULL);
- } else {
- xml_unexpected_start_tag(p, name, "property");
- }
-}
-
-static void XMLCALL
tmx_layer_el_start(void *pv, const char *name, const char **attr)
{
XML_Parser p = (XML_Parser) pv;
@@ -1080,61 +796,3 @@ tmx_object_spawn_end(void *pv, const char *name)
xml_unexpected_end_tag(p, name, "object");
}
}
-
-static void XMLCALL
-tmx_unused_start(void *pv, const char *name, const char **attr)
-{
- XML_Parser p = (XML_Parser) pv;
-
-#ifdef DEBUG_TMX
- debug("<%s> (unused)", name);
-#endif
-
- /* Shut up, GCC. */
- for (; *name != '\0'; ++name);
- for (; *attr != NULL; ++attr);
-
- xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL);
-}
-
-static void XMLCALL
-tmx_unused_end(void *pv, const char *name)
-{
- XML_Parser p = (XML_Parser) pv;
-
-#ifdef DEBUG_TMX
- debug("</%s> (unused)", name);
-#endif
-
- /* Shut up, GCC. */
- for (; *name != '\0'; ++name);
-
- xml_node_pop(p);
-}
-
-static void XMLCALL
-tmx_invalid_start(void *pv, const char *name, const char **attr)
-{
- XML_Parser p = (XML_Parser) pv;
-
-#ifdef DEBUG_TMX
- debug("<%s> (invalid)", name);
-#endif
-
- /* Shut up, GCC. */
- for (; *attr != NULL; ++attr);
-
- xml_unexpected_start_tag(p, name, "");
-}
-
-static void XMLCALL
-tmx_invalid_end(void *pv, const char *name)
-{
- XML_Parser p = (XML_Parser) pv;
-
-#ifdef DEBUG_TMX
- debug("<%s> (invalid)", name);
-#endif
-
- xml_unexpected_end_tag(p, name, "");
-}
diff --git a/src/resources/map.h b/src/resources/map.h
index 3341aaf..73f004e 100644
--- a/src/resources/map.h
+++ b/src/resources/map.h
@@ -21,8 +21,8 @@
#include <SDL_stdinc.h>
#include "resource.h"
+#include "tileset.h"
#include "palette.h"
-#include "image.h"
enum map_palette_id {
MAP_PALETTE_DEFAULT = 0,
@@ -45,22 +45,6 @@ struct map_palette {
struct palette *palette;
Uint16 min;
};
-struct tileset {
- struct resource res;
- char *dirname;
- char *name;
- int tilewidth;
- int tileheight;
- int width;
- int height;
- enum {
- TILESET_TYPE_IMAGE,
- TILESET_TYPE_COLLISION
- } type;
- struct image *image;
- Uint8 *collision_tiles;
- int cur_collision_tile;
-};
struct map_tileset {
struct tileset *tileset;
Uint32 firstgid;
diff --git a/src/resources/tileset.c b/src/resources/tileset.c
new file mode 100644
index 0000000..05f055c
--- /dev/null
+++ b/src/resources/tileset.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2013 Patrick "P. J." McDermott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <expat.h>
+#include <config.h>
+#include "tileset.h"
+#include "resource.h"
+#include "tmx.h"
+#include "image.h"
+#include "../xml.h"
+#include "../logging.h"
+
+struct resource_table ts_res;
+
+static void XMLCALL tmx_tileset_start(void *, const char *, const char **);
+static void XMLCALL tmx_tileset_end(void *, const char *);
+static void XMLCALL tmx_image_end(void *, const char *);
+static void XMLCALL tmx_tile_end(void *, const char *);
+static void XMLCALL tmx_tile_properties_start(void *, const char *,
+ const char **);
+static void XMLCALL tmx_tile_property_start(void *, const char *,
+ const char **);
+
+struct tileset *
+tileset_get(const char *path, const char *basedir)
+{
+ struct tileset *ts;
+ XML_Parser p;
+ FILE *tmx_fp;
+ void *tmx_buf;
+ size_t len;
+ enum XML_Status status;
+
+ ts = (struct tileset *) resource_get(&ts_res, path);
+ if (ts != NULL) {
+ resource_use((struct resource *) ts);
+ return ts;
+ }
+
+ ts = resource_alloc(path, sizeof(*ts));
+ if (ts == NULL) {
+ return NULL;
+ }
+ ts->dirname = strdup(basedir);
+
+ p = XML_ParserCreate(NULL);
+ if (p == NULL) {
+ warn("Failed to create TSX parser");
+ return NULL;
+ }
+
+ XML_UseParserAsHandlerArg(p);
+ xml_node_push(p, ts, tmx_tileset_start, tmx_invalid_end, NULL);
+
+ tmx_fp = fopen(path, "rb");
+ if (tmx_fp == NULL) {
+ warn("Failed to open TSX file");
+ xml_node_pop(p);
+ XML_ParserFree(p);
+ return NULL;
+ }
+
+ tmx_buf = XML_GetBuffer(p, 8192);
+ if (tmx_buf == NULL) {
+ warn("Failed to create TSX parse buffer");
+ xml_node_pop(p);
+ XML_ParserFree(p);
+ fclose(tmx_fp);
+ return NULL;
+ }
+
+ while (!feof(tmx_fp)) {
+ len = fread(tmx_buf, 1, 8192, tmx_fp);
+ status = XML_ParseBuffer(p, len, feof(tmx_fp));
+ if (status == XML_STATUS_OK) {
+ continue;
+ }
+ warn("Failed to parse TSX file (%s)",
+ XML_ErrorString(XML_GetErrorCode(p)));
+ xml_node_pop(p);
+ XML_ParserFree(p);
+ fclose(tmx_fp);
+ return NULL;
+ }
+
+ XML_ParserFree(p);
+ fclose(tmx_fp);
+
+ resource_use((struct resource *) ts);
+ resource_add(&ts_res, path, (struct resource *) ts);
+
+ return ts;
+}
+
+void XMLCALL
+tmx_tileset_el_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p = (XML_Parser) pv;
+ struct tileset *ts;
+ char *dirname;
+ char *source;
+ char *path;
+ struct image *img;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (tileset child)", name);
+#endif
+
+ ts = xml_node_peek(p);
+
+ 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, "properties")) {
+ /* Not used by engine. */
+ xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL);
+ } else if (xml_check_tag(name, "image")) {
+ xml_get_int_attr(p, attr, "width", &ts->width, 1);
+ xml_get_int_attr(p, attr, "height", &ts->height, 1);
+ ts->width /= ts->tilewidth;
+ ts->height /= ts->tileheight;
+ img = NULL;
+ if (ts->type == TILESET_TYPE_IMAGE) {
+ dirname = ts->dirname;
+ xml_get_string_attr(p, attr, "source", &source, 0);
+ path = malloc(strlen(dirname) + strlen(source) + 2);
+ if (path == NULL) {
+ return;
+ }
+ sprintf(path, "%s/%s", dirname, source);
+ img = img_png_get(path);
+ /* TODO: Get the color key from the trans attribute. */
+ SDL_SetColorKey(img->image, SDL_SRCCOLORKEY,
+ SDL_MapRGB(img->image->format,
+ 0xFC, 0x00, 0xFF));
+ free(source);
+ } else if (ts->type == TILESET_TYPE_COLLISION) {
+ ts->collision_tiles = malloc(ts->width * ts->height *
+ sizeof(*ts->collision_tiles));
+ if (ts->collision_tiles == NULL) {
+ return;
+ }
+ }
+ xml_node_push(p, img, tmx_invalid_start, tmx_image_end, NULL);
+ } else if (xml_check_tag(name, "tile")) {
+ xml_get_int_attr(p, attr, "id", &ts->cur_collision_tile, 1);
+ xml_node_push(p, ts, tmx_tile_properties_start, tmx_tile_end,
+ NULL);
+ } else {
+ xml_unexpected_start_tag(p, name, "tileoffset, image, tile");
+ }
+}
+
+static void XMLCALL
+tmx_tileset_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p = (XML_Parser) pv;
+ struct tileset *ts;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (external tileset)", name);
+#endif
+
+ if (xml_check_tag(name, "tileset")) {
+ ts = xml_node_peek(p);
+ xml_get_string_attr(p, attr, "name", &ts->name, 1);
+ xml_get_int_attr(p, attr, "tilewidth", &ts->tilewidth, 1);
+ xml_get_int_attr(p, attr, "tileheight", &ts->tileheight, 1);
+ if (strcmp(ts->name, "collision") == 0) {
+ ts->type = TILESET_TYPE_COLLISION;
+ } else {
+ ts->type = TILESET_TYPE_IMAGE;
+ }
+ xml_node_push(p, ts, tmx_tileset_el_start, tmx_tileset_end,
+ NULL);
+ } else {
+ xml_unexpected_start_tag(p, name, "tileset");
+ }
+}
+
+static void XMLCALL
+tmx_tileset_end(void *pv, const char *name)
+{
+ XML_Parser p = (XML_Parser) pv;
+
+#ifdef DEBUG_TMX
+ debug("</%s> (external tileset)", name);
+#endif
+
+ if (xml_check_tag(name, "tileset")) {
+ xml_node_pop(p);
+ } else {
+ xml_unexpected_end_tag(p, name, "tileset");
+ }
+}
+
+static void XMLCALL
+tmx_image_end(void *pv, const char *name)
+{
+ XML_Parser p = (XML_Parser) pv;
+ struct image *img;
+ struct tileset *ts;
+
+#ifdef DEBUG_TMX
+ debug("</%s> (image)", name);
+#endif
+
+ if (xml_check_tag(name, "image")) {
+ img = (struct image *) xml_node_pop(p);
+ ts = (struct tileset *) xml_node_peek(p);
+ ts->image = img;
+ } else {
+ xml_unexpected_end_tag(p, name, "image");
+ }
+}
+
+static void XMLCALL
+tmx_tile_end(void *pv, const char *name)
+{
+ XML_Parser p = (XML_Parser) pv;
+
+#ifdef DEBUG_TMX
+ debug("</%s> (tile)", name);
+#endif
+
+ xml_node_pop(p);
+
+ if (xml_check_tag(name, "tile")) {
+ } else {
+ xml_unexpected_end_tag(p, name, "tile");
+ }
+}
+
+static void XMLCALL
+tmx_tile_properties_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p = (XML_Parser) pv;
+ struct tileset *ts;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (tile properties)", name);
+#endif
+
+ ts = xml_node_peek(p);
+
+ if (xml_check_tag(name, "properties")) {
+ /* <properties> has no attributes, but GCC warns of an
+ * "unused parameter ‘attr’". */
+ for (; 0; ++attr);
+ xml_node_push(p, ts, tmx_tile_property_start, tmx_unused_end,
+ NULL);
+ } else {
+ xml_unexpected_start_tag(p, name, "properties");
+ }
+}
+
+static void XMLCALL
+tmx_tile_property_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p = (XML_Parser) pv;
+ struct tileset *ts;
+ char *attr_name;
+ char *attr_value;
+ int coll_t, coll_r, coll_b, coll_l;
+ int n;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (tile property)", name);
+#endif
+
+ ts = xml_node_peek(p);
+
+ if (xml_check_tag(name, "property")) {
+ xml_get_string_attr(p, attr, "name", &attr_name, 1);
+ xml_get_string_attr(p, attr, "value", &attr_value, 1);
+ if (strcmp(attr_name, "collision") ==0) {
+ n = sscanf(attr_value, "%d,%d,%d,%d",
+ &coll_t, &coll_r, &coll_b, &coll_l);
+ if (n != 4) {
+ return;
+ }
+ ts->collision_tiles[ts->cur_collision_tile] =
+ coll_t << 3 | coll_r << 2 |
+ coll_b << 1 | coll_l << 0;
+ }
+ free(attr_name);
+ free(attr_value);
+ for (; 0; ++attr, ++ts);
+ xml_node_push(p, NULL, tmx_invalid_start, tmx_unused_end, NULL);
+ } else {
+ xml_unexpected_start_tag(p, name, "property");
+ }
+}
diff --git a/src/resources/tileset.h b/src/resources/tileset.h
new file mode 100644
index 0000000..b5d2c72
--- /dev/null
+++ b/src/resources/tileset.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 Patrick "P. J." McDermott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RESOURCE_TILESET_H
+#define RESOURCE_TILESET_H
+
+#include <SDL_stdinc.h>
+#include <expat.h>
+#include "resource.h"
+#include "image.h"
+
+struct tileset {
+ struct resource res;
+ char *dirname;
+ char *name;
+ int tilewidth;
+ int tileheight;
+ int width;
+ int height;
+ enum {
+ TILESET_TYPE_IMAGE,
+ TILESET_TYPE_COLLISION
+ } type;
+ struct image *image;
+ Uint8 *collision_tiles;
+ int cur_collision_tile;
+};
+
+struct tileset *tileset_get(const char *path, const char *basedir);
+void XMLCALL tmx_tileset_el_start(void *pv, const char *name,
+ const char **attr);
+
+#endif
diff --git a/src/resources/tmx.c b/src/resources/tmx.c
new file mode 100644
index 0000000..64375e3
--- /dev/null
+++ b/src/resources/tmx.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 Patrick "P. J." McDermott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <expat.h>
+#include <config.h>
+#include "tmx.h"
+#include "../xml.h"
+#include "../logging.h"
+
+void XMLCALL
+tmx_unused_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p = (XML_Parser) pv;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (unused)", name);
+#endif
+
+ /* Shut up, GCC. */
+ for (; *name != '\0'; ++name);
+ for (; *attr != NULL; ++attr);
+
+ xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL);
+}
+
+void XMLCALL
+tmx_unused_end(void *pv, const char *name)
+{
+ XML_Parser p = (XML_Parser) pv;
+
+#ifdef DEBUG_TMX
+ debug("</%s> (unused)", name);
+#endif
+
+ /* Shut up, GCC. */
+ for (; *name != '\0'; ++name);
+
+ xml_node_pop(p);
+}
+
+void XMLCALL
+tmx_invalid_start(void *pv, const char *name, const char **attr)
+{
+ XML_Parser p = (XML_Parser) pv;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (invalid)", name);
+#endif
+
+ /* Shut up, GCC. */
+ for (; *attr != NULL; ++attr);
+
+ xml_unexpected_start_tag(p, name, "");
+}
+
+void XMLCALL
+tmx_invalid_end(void *pv, const char *name)
+{
+ XML_Parser p = (XML_Parser) pv;
+
+#ifdef DEBUG_TMX
+ debug("<%s> (invalid)", name);
+#endif
+
+ xml_unexpected_end_tag(p, name, "");
+}
diff --git a/src/resources/tmx.h b/src/resources/tmx.h
new file mode 100644
index 0000000..b5db5e5
--- /dev/null
+++ b/src/resources/tmx.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 Patrick "P. J." McDermott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RESOURCE_TMX_H
+#define RESOURCE_TMX_H
+
+#include <expat.h>
+
+void XMLCALL tmx_unused_start(void *pv, const char *name, const char **attr);
+void XMLCALL tmx_unused_end(void *pv, const char *name);
+void XMLCALL tmx_invalid_start(void *pv, const char *name, const char **attr);
+void XMLCALL tmx_invalid_end(void *pv, const char *name);
+
+#endif