*/
private MapLayer readLayer(Node t) throws Exception {
final int layerWidth = getAttribute(t, "width", map.getWidth());
final int layerHeight = getAttribute(t, "height", map.getHeight());
TileLayer ml = new TileLayer(layerWidth, layerHeight);
final int offsetX = getAttribute(t, "x", 0);
final int offsetY = getAttribute(t, "y", 0);
final int visible = getAttribute(t, "visible", 1);
String opacity = getAttributeValue(t, "opacity");
ml.setName(getAttributeValue(t, "name"));
if (opacity != null) {
ml.setOpacity(Float.parseFloat(opacity));
}
readProperties(t.getChildNodes(), ml.getProperties());
for (Node child = t.getFirstChild(); child != null; child = child.getNextSibling()) {
String nodeName = child.getNodeName();
if ("data".equalsIgnoreCase(nodeName)) {
String encoding = getAttributeValue(child, "encoding");
if (encoding != null && "base64".equalsIgnoreCase(encoding)) {
Node cdata = child.getFirstChild();
if (cdata == null) {
Log.ger.warn("layer <data> tag enclosed no data. (empty data tag)");
} else {
char[] enc = cdata.getNodeValue().trim().toCharArray();
byte[] dec = Base64.decode(enc);
ByteArrayInputStream bais = new ByteArrayInputStream(dec);
InputStream is;
String comp = getAttributeValue(child, "compression");
if (comp != null && "gzip".equalsIgnoreCase(comp)) {
is = new GZIPInputStream(bais);
} else {
is = bais;
}
for (int y = 0; y < ml.getHeight(); y++) {
for (int x = 0; x < ml.getWidth(); x++) {
int tileId = 0;
tileId |= is.read();
tileId |= is.read() << 8;
tileId |= is.read() << 16;
tileId |= is.read() << 24;
TileSet ts = map.findTileSetForTileGID(tileId);
if (ts != null) {
ml.setTileAt(x, y, ts.getTile(tileId - ts.getFirstGid()));
} else {
ml.setTileAt(x, y, null);
}
}
}
}
} else {
int x = 0, y = 0;
for (Node dataChild = child.getFirstChild(); dataChild != null; dataChild = dataChild.getNextSibling()) {
if ("tile".equalsIgnoreCase(dataChild.getNodeName())) {
int tileId = getAttribute(dataChild, "gid", -1);
TileSet ts = map.findTileSetForTileGID(tileId);
if (ts != null) {
ml.setTileAt(x, y, ts.getTile(tileId - ts.getFirstGid()));
} else {
ml.setTileAt(x, y, null);
}
x++;
if (x == ml.getWidth()) {
x = 0;
y++;
}
if (y == ml.getHeight()) {
break;
}
}
}
}
} else if ("tileproperties".equalsIgnoreCase(nodeName)) {
for (Node tpn = child.getFirstChild(); tpn != null; tpn = tpn.getNextSibling()) {
if ("tile".equalsIgnoreCase(tpn.getNodeName())) {
int x = getAttribute(tpn, "x", -1);
int y = getAttribute(tpn, "y", -1);
Properties tip = new Properties();
readProperties(tpn.getChildNodes(), tip);
ml.setTileInstancePropertiesAt(x, y, tip);
}
}
}
}
// This is done at the end, otherwise the offset is applied during
// the loading of the tiles.
ml.setOffset(offsetX, offsetY);
// Invisible layers are automatically locked, so it is important to
// set the layer to potentially invisible _after_ the layer data is
// loaded.
// todo: Shouldn't this be just a user interface feature, rather than
// todo: something to keep in mind at this level?
ml.setVisible(visible == 1);
return ml;
}