summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2008-04-08 18:43:44 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2008-04-08 18:43:44 +0000
commit720f716ba8d98a85266b8e81a534737c6fcdcf5f (patch)
tree192c702c463db0661f42fa34addf8f957e19e169
parentf25d5640eba5b1a0bbbc050a858aa4cdbdffdc7f (diff)
downloadmana-client-720f716ba8d98a85266b8e81a534737c6fcdcf5f.tar.gz
mana-client-720f716ba8d98a85266b8e81a534737c6fcdcf5f.tar.bz2
mana-client-720f716ba8d98a85266b8e81a534737c6fcdcf5f.tar.xz
mana-client-720f716ba8d98a85266b8e81a534737c6fcdcf5f.zip
Implemented support for an arbitrary number of map layers. The only layer
requirement for map layers are now that the fringe layer is called "Fringe" and that the collision layer is called "Collision".
-rw-r--r--ChangeLog10
-rw-r--r--src/gui/viewport.cpp24
-rw-r--r--src/map.cpp208
-rw-r--r--src/map.h110
-rw-r--r--src/resources/imageset.cpp2
-rw-r--r--src/resources/imageset.h14
-rw-r--r--src/resources/mapreader.cpp151
-rw-r--r--src/resources/mapreader.h4
-rw-r--r--src/tileset.h3
9 files changed, 298 insertions, 228 deletions
diff --git a/ChangeLog b/ChangeLog
index 6acb5e22..597a5c0c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-04-08 Bjørn Lindeijer <bjorn@lindeijer.nl>
+
+ * src/map.cpp, src/gui/viewport.cpp, src/tileset.h, src/map.h,
+ src/resources/imageset.cpp, src/resources/mapreader.cpp,
+ src/resources/imageset.h, src/resources/mapreader.h,
+ data/maps/new_3-1.tmx, data/maps/new_1-1.tmx: Implemented support for
+ an arbitrary number of map layers. The only layer requirement for map
+ layers are now that the fringe layer is called "Fringe" and that the
+ collision layer is called "Collision".
+
2008-04-07 Bjørn Lindeijer <bjorn@lindeijer.nl>
* src/particle.cpp, src/utils/xml.cpp, src/utils/xml.h,
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 7c68b577..33449659 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -48,6 +48,8 @@
#include <cassert>
+extern volatile int tick_time;
+
Viewport::Viewport():
mMap(0),
mViewX(0.0f),
@@ -214,25 +216,17 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
// Draw tiles and sprites
if (mMap)
{
- mMap->draw(graphics, (int) mViewX, (int) mViewY, 0);
- drawTargetCursor(graphics);
- mMap->draw(graphics, (int) mViewX, (int) mViewY, 1);
- mMap->draw(graphics, (int) mViewX, (int) mViewY, 2);
- if (mShowDebugPath)
- {
- mMap->drawCollision(graphics, (int) mViewX, (int) mViewY);
- }
- mMap->drawOverlay(graphics, mViewX, mViewY,
- (int) config.getValue("OverlayDetail", 2));
+ mMap->draw(graphics, (int) mViewX, (int) mViewY);
+ drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite
drawTargetName(graphics);
- }
- if (mShowDebugPath && mMap)
- {
- drawDebugPath(graphics);
+ if (mShowDebugPath) {
+ mMap->drawCollision(graphics, (int) mViewX, (int) mViewY);
+ drawDebugPath(graphics);
+ }
}
- // Draw player nickname, speech, and emotion sprite as needed
+ // Draw player names, speech, and emotion sprite as needed
Beings &beings = beingManager->getAll();
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
diff --git a/src/map.cpp b/src/map.cpp
index c7d1d3b8..28d07022 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -28,6 +28,7 @@
#include <cassert>
#include "beingmanager.h"
+#include "configuration.h"
#include "game.h"
#include "graphics.h"
#include "particle.h"
@@ -41,6 +42,8 @@
#include "utils/dtor.h"
#include "utils/tostring.h"
+extern volatile int tick_time;
+
/**
* A location on a tile map. Used for pathfinding, open list.
*/
@@ -63,6 +66,80 @@ struct Location
MetaTile *tile;
};
+MapLayer::MapLayer(int x, int y, int width, int height, bool isFringeLayer):
+ mX(x), mY(y),
+ mWidth(width), mHeight(height),
+ mIsFringeLayer(isFringeLayer)
+{
+ const int size = mWidth * mHeight;
+ mTiles = new Image*[size];
+ std::fill_n(mTiles, size, (Image*) 0);
+}
+
+MapLayer::~MapLayer()
+{
+ delete[] mTiles;
+}
+
+void MapLayer::setTile(int x, int y, Image *img)
+{
+ mTiles[x + y * mWidth] = img;
+}
+
+Image* MapLayer::getTile(int x, int y) const
+{
+ return mTiles[x + y * mWidth];
+}
+
+void MapLayer::draw(Graphics *graphics,
+ int startX, int startY,
+ int endX, int endY,
+ int scrollX, int scrollY,
+ const Sprites &sprites) const
+{
+ startX -= mX;
+ startY -= mY;
+ endX -= mX;
+ endY -= mY;
+
+ if (startX < 0) startX = 0;
+ if (startY < 0) startY = 0;
+ if (endX > mWidth) endX = mWidth;
+ if (endY > mHeight) endY = mHeight;
+
+ Sprites::const_iterator si = sprites.begin();
+
+ for (int y = startY; y < endY; y++)
+ {
+ // If drawing the fringe layer, make sure all sprites above this row of
+ // tiles have been drawn
+ if (mIsFringeLayer) {
+ while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) {
+ (*si)->draw(graphics, -scrollX, -scrollY);
+ si++;
+ }
+ }
+
+ for (int x = startX; x < endX; x++)
+ {
+ Image *img = getTile(x, y);
+ if (img) {
+ const int px = (x + mX) * 32 - scrollX;
+ const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight();
+ graphics->drawImage(img, px, py);
+ }
+ }
+ }
+
+ // Draw any remaining sprites
+ if (mIsFringeLayer) {
+ while (si != sprites.end()) {
+ (*si)->draw(graphics, -scrollX, -scrollY);
+ si++;
+ }
+ }
+}
+
Map::Map(int width, int height, int tileWidth, int tileHeight):
mWidth(width), mHeight(height),
mTileWidth(tileWidth), mTileHeight(tileHeight),
@@ -70,31 +147,26 @@ Map::Map(int width, int height, int tileWidth, int tileHeight):
mOnClosedList(1), mOnOpenList(2),
mLastScrollX(0.0f), mLastScrollY(0.0f)
{
- int size = mWidth * mHeight;
+ const int size = mWidth * mHeight;
mMetaTiles = new MetaTile[size];
- for (int i=0; i < NB_BLOCKTYPES; i++)
+ for (int i = 0; i < NB_BLOCKTYPES; i++)
{
mOccupation[i] = new int[size];
memset(mOccupation[i], 0, size * sizeof(int));
}
- mTiles = new Image*[size * 3];
- std::fill_n(mTiles, size * 3, (Image*)0);
}
Map::~Map()
{
- // clean up map data
+ // delete metadata, layers, tilesets and overlays
delete[] mMetaTiles;
- delete[] mTiles;
for (int i=0; i < NB_BLOCKTYPES; i++)
{
delete[] mOccupation[i];
}
- // clean up tilesets
+ for_each(mLayers.begin(), mLayers.end(), make_dtor(mLayers));
for_each(mTilesets.begin(), mTilesets.end(), make_dtor(mTilesets));
- mTilesets.clear();
- // clean up overlays
for_each(mOverlays.begin(), mOverlays.end(), make_dtor(mOverlays));
}
@@ -109,9 +181,9 @@ void Map::initializeOverlays()
const std::string name = "overlay" + toString(i);
Image *img = resman->getImage(getProperty(name + "image"));
- float speedX = getFloatProperty(name + "scrollX");
- float speedY = getFloatProperty(name + "scrollY");
- float parallax = getFloatProperty(name + "parallax");
+ const float speedX = getFloatProperty(name + "scrollX");
+ const float speedY = getFloatProperty(name + "scrollY");
+ const float parallax = getFloatProperty(name + "parallax");
if (img)
{
@@ -124,6 +196,11 @@ void Map::initializeOverlays()
}
}
+void Map::addLayer(MapLayer *layer)
+{
+ mLayers.push_back(layer);
+}
+
void Map::addTileset(Tileset *tileset)
{
mTilesets.push_back(tileset);
@@ -137,63 +214,31 @@ bool spriteCompare(const Sprite *a, const Sprite *b)
return a->getPixelY() < b->getPixelY();
}
-void Map::draw(Graphics *graphics, int scrollX, int scrollY, int layer)
+void Map::draw(Graphics *graphics, int scrollX, int scrollY)
{
int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1;
- // If drawing the fringe layer, make sure sprites are sorted
- SpriteIterator si;
- if (layer == 1)
- {
- mSprites.sort(spriteCompare);
- si = mSprites.begin();
- endPixelY += mMaxTileHeight - mTileHeight;
- }
+ // TODO: Do this per-layer
+ endPixelY += mMaxTileHeight - mTileHeight;
int startX = scrollX / mTileWidth;
int startY = scrollY / mTileHeight;
int endX = (graphics->getWidth() + scrollX + mTileWidth - 1) / mTileWidth;
int endY = endPixelY / mTileHeight;
- if (startX < 0) startX = 0;
- if (startY < 0) startY = 0;
- if (endX > mWidth) endX = mWidth;
- if (endY > mHeight) endY = mHeight;
+ // Make sure sprites are sorted
+ mSprites.sort(spriteCompare);
- for (int y = startY; y < endY; y++)
- {
- // If drawing the fringe layer, make sure all sprites above this row of
- // tiles have been drawn
- if (layer == 1)
- {
- while (si != mSprites.end() && (*si)->getPixelY() <= y * 32 - 32)
- {
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
- }
- }
-
- for (int x = startX; x < endX; x++)
- {
- Image *img = getTile(x, y, layer);
- if (img) {
- graphics->drawImage(img,
- x * mTileWidth - scrollX,
- y * mTileHeight - scrollY +
- mTileHeight - img->getHeight());
- }
- }
+ Layers::const_iterator layeri = mLayers.begin();
+ for (; layeri != mLayers.end(); ++layeri) {
+ (*layeri)->draw(graphics,
+ startX, startY, endX, endY,
+ scrollX, scrollY,
+ mSprites);
}
- // Draw any remaining sprites
- if (layer == 1)
- {
- while (si != mSprites.end())
- {
- (*si)->draw(graphics, -scrollX, -scrollY);
- si++;
- }
- }
+ drawOverlay(graphics, scrollX, scrollY,
+ (int) config.getValue("OverlayDetail", 2));
}
void Map::drawCollision(Graphics *graphics, int scrollX, int scrollY)
@@ -289,26 +334,10 @@ void Map::drawOverlay(Graphics *graphics,
};
}
-void Map::setTileWithGid(int x, int y, int layer, int gid)
-{
- if (layer == 3)
- {
- Tileset *set = getTilesetWithGid(gid);
- if (set && (gid - set->getFirstGid() != 0))
- {
- blockTile(x, y, BLOCKTYPE_WALL);
- }
- }
- else if (layer < 3)
- {
- setTile(x, y, layer, getTileWithGid(gid));
- }
-}
-
class ContainsGidFunctor
{
public:
- bool operator() (Tileset* set)
+ bool operator() (const Tileset* set) const
{
return (set->getFirstGid() <= gid &&
gid - set->getFirstGid() < (int)set->size());
@@ -326,17 +355,6 @@ Tileset* Map::getTilesetWithGid(int gid) const
return (i == mTilesets.end()) ? NULL : *i;
}
-Image* Map::getTileWithGid(int gid) const
-{
- Tileset *set = getTilesetWithGid(gid);
-
- if (set) {
- return set->get(gid - set->getFirstGid());
- }
-
- return NULL;
-}
-
void Map::blockTile(int x, int y, BlockType type)
{
if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight)
@@ -412,16 +430,6 @@ bool Map::contains(int x, int y) const
return x >= 0 && y >= 0 && x < mWidth && y < mHeight;
}
-void Map::setTile(int x, int y, int layer, Image *img)
-{
- mTiles[x + y * mWidth + layer * (mWidth * mHeight)] = img;
-}
-
-Image* Map::getTile(int x, int y, int layer) const
-{
- return mTiles[x + y * mWidth + layer * (mWidth * mHeight)];
-}
-
MetaTile* Map::getMetaTile(int x, int y) const
{
return &mMetaTiles[x + y * mWidth];
@@ -484,8 +492,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w
for (int dx = -1; dx <= 1; dx++)
{
// Calculate location of tile to check
- int x = curr.x + dx;
- int y = curr.y + dy;
+ const int x = curr.x + dx;
+ const int y = curr.y + dy;
// Skip if if we're checking the same tile we're leaving from,
// or if the new location falls outside of the map boundaries
@@ -559,7 +567,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w
// Update Gcost and Fcost of new tile
newTile->Gcost = Gcost;
- newTile->Fcost = newTile->Gcost + newTile->Hcost;
+ newTile->Fcost = Gcost + newTile->Hcost;
if (x != destX || y != destY) {
// Add this tile to the open list
@@ -576,7 +584,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w
// Found a shorter route.
// Update Gcost and Fcost of the new tile
newTile->Gcost = Gcost;
- newTile->Fcost = newTile->Gcost + newTile->Hcost;
+ newTile->Fcost = Gcost + newTile->Hcost;
// Set the current tile as the parent of the new tile
newTile->parentX = curr.x;
@@ -617,7 +625,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w
return path;
}
-void Map::addParticleEffect (std::string effectFile, int x, int y)
+void Map::addParticleEffect(const std::string &effectFile, int x, int y)
{
ParticleEffectData newEffect;
newEffect.file = effectFile;
diff --git a/src/map.h b/src/map.h
index 126cb70b..31c6be00 100644
--- a/src/map.h
+++ b/src/map.h
@@ -32,6 +32,7 @@
class AmbientOverlay;
class Graphics;
class Image;
+class MapLayer;
class Particle;
class Sprite;
class Tileset;
@@ -41,8 +42,7 @@ struct PATH_NODE;
typedef std::vector<Tileset*> Tilesets;
typedef std::list<Sprite*> Sprites;
typedef Sprites::iterator SpriteIterator;
-
-extern volatile int tick_time;
+typedef std::vector<MapLayer*> Layers;
/**
* A meta tile stores additional information about a location on a tile map.
@@ -67,6 +67,56 @@ struct MetaTile
};
/**
+ * A map layer. Stores a grid of tiles and their offset, and implements layer
+ * rendering.
+ */
+class MapLayer
+{
+ public:
+ /**
+ * Constructor, taking layer origin, size and whether this layer is the
+ * fringe layer. The fringe layer is the layer that draws the sprites.
+ * There can be only one fringe layer per map.
+ */
+ MapLayer(int x, int y, int width, int height, bool isFringeLayer);
+
+ /**
+ * Destructor.
+ */
+ ~MapLayer();
+
+ /**
+ * Set tile image, with x and y in layer coordinates.
+ */
+ void setTile(int x, int y, Image *img);
+
+ /**
+ * Get tile image, with x and y in layer coordinates.
+ */
+ Image *getTile(int x, int y) const;
+
+ /**
+ * Draws this layer to the given graphics context. The coordinates are
+ * expected to be in map range and will be translated to local layer
+ * coordinates and clipped to the layer's dimensions.
+ *
+ * The given sprites are only drawn when this layer is the fringe
+ * layer.
+ */
+ void draw(Graphics *graphics,
+ int startX, int startY,
+ int endX, int endY,
+ int scrollX, int scrollY,
+ const Sprites &sprites) const;
+
+ private:
+ int mX, mY;
+ int mWidth, mHeight;
+ bool mIsFringeLayer; /**< Whether the sprites are drawn. */
+ Image **mTiles;
+};
+
+/**
* A tile map.
*/
class Map : public Properties
@@ -98,9 +148,14 @@ class Map : public Properties
void initializeOverlays();
/**
- * Draws a map layer to the given graphics output.
+ * Draws the map to the given graphics output. This method draws all
+ * layers, sprites and overlay effects.
+ *
+ * TODO: For efficiency reasons, this method could take into account
+ * the clipping rectangle set on the Graphics object. However,
+ * currently the map is always drawn full-screen.
*/
- void draw(Graphics *graphics, int scrollX, int scrollY, int layer);
+ void draw(Graphics *graphics, int scrollX, int scrollY);
/**
* Visualizes collision layer for debugging
@@ -108,34 +163,20 @@ class Map : public Properties
void drawCollision(Graphics *graphics, int scrollX, int scrollY);
/**
- * Draws the overlay graphic to the given graphics output.
- */
- void
- drawOverlay(Graphics *graphics, float scrollX, float scrollY,
- int detail);
-
- /**
- * Adds a tileset to this map.
- */
- void
- addTileset(Tileset *tileset);
-
- /**
- * Sets a tile using a global tile id. Used by the layer loading
- * routine.
+ * Adds a layer to this map. The map takes ownership of the layer.
*/
- void
- setTileWithGid(int x, int y, int layer, int gid);
+ void addLayer(MapLayer *layer);
/**
- * Set tile ID.
+ * Adds a tileset to this map. The map takes ownership of the tileset.
*/
- void setTile(int x, int y, int layer, Image *img);
+ void addTileset(Tileset *tileset);
/**
- * Get tile ID.
+ * Finds the tile set that a tile with the given global id is part of.
*/
- Image *getTile(int x, int y, int layer) const;
+ Tileset*
+ getTilesetWithGid(int gid) const;
/**
* Get tile reference.
@@ -203,7 +244,7 @@ class Map : public Properties
/**
* Adds a particle effect
*/
- void addParticleEffect (std::string effectFile, int x, int y);
+ void addParticleEffect(const std::string &effectFile, int x, int y);
/**
* Initializes all added particle effects
@@ -213,15 +254,11 @@ class Map : public Properties
private:
/**
- * Converts a global tile id to the Image* pointing to the associated
- * tile image.
- */
- Image* getTileWithGid(int gid) const;
-
- /**
- * Finds the tile set that a tile with the given global id is part of.
+ * Draws the overlay graphic to the given graphics output.
*/
- Tileset* getTilesetWithGid(int gid) const;
+ void
+ drawOverlay(Graphics *graphics, float scrollX, float scrollY,
+ int detail);
/**
* Tells whether the given coordinates fall within the map boundaries.
@@ -243,15 +280,14 @@ class Map : public Properties
int mTileWidth, mTileHeight;
int mMaxTileHeight;
MetaTile *mMetaTiles;
- Image **mTiles;
-
+ Layers mLayers;
Tilesets mTilesets;
Sprites mSprites;
// Pathfinding members
int mOnClosedList, mOnOpenList;
- // Overlay Data
+ // Overlay data
std::list<AmbientOverlay*> mOverlays;
float mLastScrollX;
float mLastScrollY;
diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp
index 08a6a110..5618abfa 100644
--- a/src/resources/imageset.cpp
+++ b/src/resources/imageset.cpp
@@ -50,7 +50,7 @@ ImageSet::~ImageSet()
}
Image*
-ImageSet::get(size_type i)
+ImageSet::get(size_type i) const
{
if (i >= mImages.size())
{
diff --git a/src/resources/imageset.h b/src/resources/imageset.h
index 15c21d90..fa1840ec 100644
--- a/src/resources/imageset.h
+++ b/src/resources/imageset.h
@@ -47,14 +47,20 @@ class ImageSet : public Resource
*/
~ImageSet();
- int getWidth() { return mWidth; };
+ /**
+ * Returns the width of the images in the image set.
+ */
+ int getWidth() const { return mWidth; };
- int getHeight() { return mHeight; };
+ /**
+ * Returns the height of the images in the image set.
+ */
+ int getHeight() const { return mHeight; };
typedef std::vector<Image*>::size_type size_type;
- Image* get(size_type i);
+ Image* get(size_type i) const;
- size_type size() { return mImages.size(); }
+ size_type size() const { return mImages.size(); }
private:
std::vector<Image*> mImages;
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index 3864580b..9c6c52aa 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -206,20 +206,17 @@ MapReader::readMap(const std::string &filename)
Map*
MapReader::readMap(xmlNodePtr node, const std::string &path)
{
- xmlChar *prop;
-
// Take the filename off the path
- std::string pathDir = path.substr(0, path.rfind("/") + 1);
+ const std::string pathDir = path.substr(0, path.rfind("/") + 1);
- prop = xmlGetProp(node, BAD_CAST "version");
- xmlFree(prop);
+ //xmlChar *prop = xmlGetProp(node, BAD_CAST "version");
+ //xmlFree(prop);
- int w = XML::getProperty(node, "width", 0);
- int h = XML::getProperty(node, "height", 0);
- int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
- int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
- int layerNr = 0;
- Map *map = new Map(w, h, tilew, tileh);
+ const int w = XML::getProperty(node, "width", 0);
+ const int h = XML::getProperty(node, "height", 0);
+ const int tw = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
+ const int th = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
+ Map *map = new Map(w, h, tw, th);
for_each_xml_child_node(childNode, node)
{
@@ -232,9 +229,7 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
}
else if (xmlStrEqual(childNode->name, BAD_CAST "layer"))
{
- logger->log("- Loading layer %d", layerNr);
- readLayer(childNode, map, layerNr);
- layerNr++;
+ readLayer(childNode, map);
}
else if (xmlStrEqual(childNode->name, BAD_CAST "properties"))
{
@@ -246,7 +241,8 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
{
if (xmlStrEqual(objectNode->name, BAD_CAST "object"))
{
- std::string objType = XML::getProperty(objectNode, "type", "");
+ const std::string objType =
+ XML::getProperty(objectNode, "type", "");
if (objType == "WARP" || objType == "NPC" ||
objType == "SCRIPT" || objType == "SPAWN")
@@ -255,9 +251,10 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
continue;
}
- std::string objName = XML::getProperty(objectNode, "name", "");
- int objX = XML::getProperty(objectNode, "x", 0);
- int objY = XML::getProperty(objectNode, "y", 0);
+ const std::string objName =
+ XML::getProperty(objectNode, "name", "");
+ const int objX = XML::getProperty(objectNode, "x", 0);
+ const int objY = XML::getProperty(objectNode, "y", 0);
logger->log("- Loading object name: %s type: %s at %d:%d",
objName.c_str(), objType.c_str(), objX, objY);
@@ -288,43 +285,67 @@ MapReader::readProperties(xmlNodePtr node, Properties* props)
continue;
// Example: <property name="name" value="value"/>
- xmlChar *name = xmlGetProp(childNode, BAD_CAST "name");
- xmlChar *value = xmlGetProp(childNode, BAD_CAST "value");
+ const std::string name = XML::getProperty(childNode, "name", "");
+ const std::string value = XML::getProperty(childNode, "value", "");
- if (name && value) {
- props->setProperty((const char*)name, (const char*)value);
- }
+ if (!name.empty() && !value.empty())
+ props->setProperty(name, value);
+ }
+}
- if (name) xmlFree(name);
- if (value) xmlFree(value);
+static void setTile(Map *map, MapLayer *layer, int x, int y, int gid)
+{
+ const Tileset * const set = map->getTilesetWithGid(gid);
+ if (layer) {
+ // Set regular tile on a layer
+ Image * const img = set ? set->get(gid - set->getFirstGid()) : 0;
+ layer->setTile(x, y, img);
+ } else {
+ // Set collision tile
+ if (set && (gid - set->getFirstGid() != 0))
+ map->blockTile(x, y, Map::BLOCKTYPE_WALL);
}
}
void
-MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
+MapReader::readLayer(xmlNodePtr node, Map *map)
{
- int h = map->getHeight();
- int w = map->getWidth();
+ // Layers are not necessarily the same size as the map
+ const int w = XML::getProperty(node, "width", map->getWidth());
+ const int h = XML::getProperty(node, "height", map->getHeight());
+ const int offsetX = XML::getProperty(node, "xoffset", 0);
+ const int offsetY = XML::getProperty(node, "yoffset", 0);
+ const std::string name = XML::getProperty(node, "name", "");
+
+ const bool isFringeLayer = (name == "Fringe");
+ const bool isCollisionLayer = (name == "Collision");
+
+ MapLayer *layer = 0;
+
+ if (!isCollisionLayer) {
+ layer = new MapLayer(offsetX, offsetY, w, h, isFringeLayer);
+ map->addLayer(layer);
+ }
+
+ logger->log("- Loading layer \"%s\"", name.c_str());
int x = 0;
int y = 0;
- // Load the tile data. Layers are assumed to be map size, with (0,0) as
- // origin.
+ // Load the tile data
for_each_xml_child_node(childNode, node)
{
if (!xmlStrEqual(childNode->name, BAD_CAST "data"))
continue;
- xmlChar *encoding = xmlGetProp(childNode, BAD_CAST "encoding");
- xmlChar *compression = xmlGetProp(childNode, BAD_CAST "compression");
+ const std::string encoding =
+ XML::getProperty(childNode, "encoding", "");
+ const std::string compression =
+ XML::getProperty(childNode, "compression", "");
- if (encoding && xmlStrEqual(encoding, BAD_CAST "base64"))
+ if (encoding == "base64")
{
- xmlFree(encoding);
-
- if (compression && !xmlStrEqual(compression, BAD_CAST "gzip")) {
+ if (!compression.empty() && compression != "gzip") {
logger->log("Warning: only gzip layer compression supported!");
- xmlFree(compression);
return;
}
@@ -356,34 +377,29 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
delete[] charData;
if (binData) {
- if (compression) {
- if (xmlStrEqual(compression, BAD_CAST "gzip")) {
- // Inflate the gzipped layer data
- unsigned char *inflated;
- unsigned int inflatedSize =
- inflateMemory(binData, binLen, inflated);
-
- free(binData);
- binData = inflated;
- binLen = inflatedSize;
-
- if (inflated == NULL)
- {
- logger->log("Error: Could not decompress layer!");
- xmlFree(compression);
- return;
- }
+ if (compression == "gzip") {
+ // Inflate the gzipped layer data
+ unsigned char *inflated;
+ unsigned int inflatedSize =
+ inflateMemory(binData, binLen, inflated);
+
+ free(binData);
+ binData = inflated;
+ binLen = inflatedSize;
+
+ if (!inflated) {
+ logger->log("Error: Could not decompress layer!");
+ return;
}
- xmlFree(compression);
}
for (int i = 0; i < binLen - 3; i += 4) {
- int gid = binData[i] |
+ const int gid = binData[i] |
binData[i + 1] << 8 |
binData[i + 2] << 16 |
binData[i + 3] << 24;
- map->setTileWithGid(x, y, layer, gid);
+ setTile(map, layer, x, y, gid);
x++;
if (x == w) {x = 0; y++;}
@@ -398,8 +414,8 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
if (!xmlStrEqual(childNode2->name, BAD_CAST "tile"))
continue;
- int gid = XML::getProperty(childNode2, "gid", -1);
- map->setTileWithGid(x, y, layer, gid);
+ const int gid = XML::getProperty(childNode2, "gid", -1);
+ setTile(map, layer, x, y, gid);
x++;
if (x == w) {
@@ -431,20 +447,20 @@ MapReader::readTileset(xmlNodePtr node,
return NULL;
}
- int firstGid = XML::getProperty(node, "firstgid", 0);
- int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
- int th = XML::getProperty(node, "tileheight", map->getTileHeight());
+ const int firstGid = XML::getProperty(node, "firstgid", 0);
+ const int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
+ const int th = XML::getProperty(node, "tileheight", map->getTileHeight());
for_each_xml_child_node(childNode, node)
{
if (!xmlStrEqual(childNode->name, BAD_CAST "image"))
continue;
- xmlChar* source = xmlGetProp(childNode, BAD_CAST "source");
+ const std::string source = XML::getProperty(childNode, "source", "");
- if (source)
+ if (!source.empty())
{
- std::string sourceStr = std::string((const char*)source);
+ std::string sourceStr = source;
sourceStr.erase(0, 3); // Remove "../"
ResourceManager *resman = ResourceManager::getInstance();
@@ -454,14 +470,15 @@ MapReader::readTileset(xmlNodePtr node,
{
Tileset *set = new Tileset(tilebmp, tw, th, firstGid);
tilebmp->decRef();
- xmlFree(source);
return set;
}
else {
- logger->log("Warning: Failed to load tileset (%s)", source);
+ logger->log("Warning: Failed to load tileset (%s)",
+ source.c_str());
}
}
+ // Only one image element expected
break;
}
diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h
index d16ff1d5..60056358 100644
--- a/src/resources/mapreader.h
+++ b/src/resources/mapreader.h
@@ -63,10 +63,10 @@ class MapReader
readProperties(xmlNodePtr node, Properties* props);
/**
- * Reads a map layer.
+ * Reads a map layer and adds it to the given map.
*/
static void
- readLayer(xmlNodePtr node, Map *map, int layer);
+ readLayer(xmlNodePtr node, Map *map);
/**
* Reads a tile set.
diff --git a/src/tileset.h b/src/tileset.h
index 6af69235..625fac1b 100644
--- a/src/tileset.h
+++ b/src/tileset.h
@@ -44,8 +44,7 @@ class Tileset : public ImageSet
/**
* Returns the first gid.
*/
- int
- getFirstGid()
+ int getFirstGid() const
{
return mFirstGid;
}