package org.andengine.extension.tmx;
import java.io.IOException;
import java.util.ArrayList;
import org.andengine.entity.primitive.Vector2;
import org.andengine.extension.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.andengine.extension.tmx.util.constants.TMXConstants;
import org.andengine.extension.tmx.util.exception.TMXParseException;
import org.andengine.extension.tmx.util.exception.TSXLoadException;
import org.andengine.opengl.texture.TextureManager;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.SAXUtils;
import org.andengine.util.debug.Debug;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.content.res.AssetManager;
import android.util.Log;
/**
* (c) 2010 Nicolas Gramlich (c) 2011 Zynga Inc.
*
* @author Nicolas Gramlich
* @since 19:11:29 - 20.07.2010
*/
public class TMXParser extends DefaultHandler implements TMXConstants {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final AssetManager mAssetManager;
private final TextureManager mTextureManager;
private final TextureOptions mTextureOptions;
private final VertexBufferObjectManager mVertexBufferObjectManager;
private final ITMXTilePropertiesListener mTMXTilePropertyListener;
private TMXTiledMap mTMXTiledMap;
private int mLastTileSetTileID;
private final StringBuilder mStringBuilder = new StringBuilder();
private String mDataEncoding;
private String mDataCompression;
private boolean mInMap;
private boolean mInTileset;
@SuppressWarnings("unused")
private boolean mInImage;
private boolean mInTile;
private boolean mInProperties;
@SuppressWarnings("unused")
private boolean mInProperty;
private boolean mInLayer;
private boolean mInData;
private boolean mInObjectGroup;
private boolean mInObject;
private boolean mInPolyLine;
// ===========================================================
// Constructors
// ===========================================================
public TMXParser(final AssetManager pAssetManager,
final TextureManager pTextureManager,
final TextureOptions pTextureOptions,
final VertexBufferObjectManager pVertexBufferObjectManager,
final ITMXTilePropertiesListener pTMXTilePropertyListener) {
this.mAssetManager = pAssetManager;
this.mTextureManager = pTextureManager;
this.mTextureOptions = pTextureOptions;
this.mVertexBufferObjectManager = pVertexBufferObjectManager;
this.mTMXTilePropertyListener = pTMXTilePropertyListener;
}
// ===========================================================
// Getter & Setter
// ===========================================================
TMXTiledMap getTMXTiledMap() {
return this.mTMXTiledMap;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public void startElement(final String pUri, final String pLocalName,
final String pQualifiedName, final Attributes pAttributes)
throws SAXException {
if (pLocalName.equals(TMXConstants.TAG_MAP)) {
this.mInMap = true;
this.mTMXTiledMap = new TMXTiledMap(pAttributes);
} else if (pLocalName.equals(TMXConstants.TAG_TILESET)) {
this.mInTileset = true;
final TMXTileSet tmxTileSet;
final String tsxTileSetSource = pAttributes.getValue("",
TMXConstants.TAG_TILESET_ATTRIBUTE_SOURCE);
if (tsxTileSetSource == null) {
tmxTileSet = new TMXTileSet(pAttributes, this.mTextureOptions);
} else {
try {
final int firstGlobalTileID = SAXUtils.getIntAttribute(
pAttributes,
TMXConstants.TAG_TILESET_ATTRIBUTE_FIRSTGID, 1);
final TSXLoader tsxLoader = new TSXLoader(
this.mAssetManager, this.mTextureManager,
this.mTextureOptions);
tmxTileSet = tsxLoader.loadFromAsset(firstGlobalTileID,
tsxTileSetSource);
} catch (final TSXLoadException e) {
throw new TMXParseException(
"Failed to load TMXTileSet from source: "
+ tsxTileSetSource, e);
}
}
this.mTMXTiledMap.addTMXTileSet(tmxTileSet);
} else if (pLocalName.equals(TMXConstants.TAG_IMAGE)) {
this.mInImage = true;
final ArrayList<TMXTileSet> tmxTileSets = this.mTMXTiledMap
.getTMXTileSets();
tmxTileSets.get(tmxTileSets.size() - 1).setImageSource(
this.mAssetManager, this.mTextureManager, pAttributes);
} else if (pLocalName.equals(TMXConstants.TAG_TILE)) {
this.mInTile = true;
if (this.mInTileset) {
this.mLastTileSetTileID = SAXUtils.getIntAttributeOrThrow(
pAttributes, TMXConstants.TAG_TILE_ATTRIBUTE_ID);
} else if (this.mInData) {
final ArrayList<TMXLayer> tmxLayers = this.mTMXTiledMap
.getTMXLayers();
tmxLayers.get(tmxLayers.size() - 1).initializeTMXTileFromXML(
pAttributes, this.mTMXTilePropertyListener);
}
} else if (pLocalName.equals(TMXConstants.TAG_PROPERTIES)) {
this.mInProperties = true;
} else if (this.mInProperties
&& pLocalName.equals(TMXConstants.TAG_PROPERTY)) {
this.mInProperty = true;
if (this.mInTile) {
final ArrayList<TMXTileSet> tmxTileSets = this.mTMXTiledMap
.getTMXTileSets();
final TMXTileSet lastTMXTileSet = tmxTileSets.get(tmxTileSets
.size() - 1);
lastTMXTileSet.addTMXTileProperty(this.mLastTileSetTileID,
new TMXTileProperty(pAttributes));
} else if (this.mInLayer) {
final ArrayList<TMXLayer> tmxLayers = this.mTMXTiledMap
.getTMXLayers();
final TMXLayer lastTMXLayer = tmxLayers
.get(tmxLayers.size() - 1);
lastTMXLayer.addTMXLayerProperty(new TMXLayerProperty(
pAttributes));
} else if (this.mInObject) {
final ArrayList<TMXObjectGroup> tmxObjectGroups = this.mTMXTiledMap
.getTMXObjectGroups();
final TMXObjectGroup lastTMXObjectGroup = tmxObjectGroups
.get(tmxObjectGroups.size() - 1);
final ArrayList<TMXObject> tmxObjects = lastTMXObjectGroup
.getTMXObjects();
final TMXObject lastTMXObject = tmxObjects.get(tmxObjects
.size() - 1);
lastTMXObject.addTMXObjectProperty(new TMXObjectProperty(
pAttributes));
} else if (this.mInObjectGroup) {
final ArrayList<TMXObjectGroup> tmxObjectGroups = this.mTMXTiledMap
.getTMXObjectGroups();
final TMXObjectGroup lastTMXObjectGroup = tmxObjectGroups
.get(tmxObjectGroups.size() - 1);
lastTMXObjectGroup
.addTMXObjectGroupProperty(new TMXObjectGroupProperty(
pAttributes));
} else if (this.mInMap) {
this.mTMXTiledMap
.addTMXTiledMapProperty(new TMXTiledMapProperty(
pAttributes));
}
} else if (pLocalName.equals(TMXConstants.TAG_LAYER)) {
this.mInLayer = true;
this.mTMXTiledMap.addTMXLayer(new TMXLayer(this.mTMXTiledMap,
pAttributes, this.mVertexBufferObjectManager));
} else if (pLocalName.equals(TMXConstants.TAG_DATA)) {
this.mInData = true;
this.mDataEncoding = pAttributes.getValue("",
TMXConstants.TAG_DATA_ATTRIBUTE_ENCODING);
this.mDataCompression = pAttributes.getValue("",
TMXConstants.TAG_DATA_ATTRIBUTE_COMPRESSION);
} else if (pLocalName.equals(TMXConstants.TAG_OBJECTGROUP)) {
this.mInObjectGroup = true;
this.mTMXTiledMap
.addTMXObjectGroup(new TMXObjectGroup(pAttributes));
} else if (pLocalName.equals(TMXConstants.TAG_OBJECT)) {
this.mInObject = true;
final ArrayList<TMXObjectGroup> tmxObjectGroups = this.mTMXTiledMap
.getTMXObjectGroups();
tmxObjectGroups.get(tmxObjectGroups.size() - 1).addTMXObject(
new TMXObject(pAttributes));
} else if (pLocalName.equals(TMXConstants.TAG_OBJECT_POLYLINE)) {
this.mInPolyLine = true;
String pointstr = pAttributes.getValue("",
TMXConstants.TAG_OBJECT_POLYLINE_ATTRIBUTE_POINTS);
String[] points = pointstr.split("\\s+");
Vector2 v2[] = new Vector2[points.length];
int i = 0;
for (String onePoint : points) {
String[] coordinates = onePoint.split(",");
v2[i] = new Vector2(Integer.parseInt(coordinates[0]),
Integer.parseInt(coordinates[1]));
i++;
}
final ArrayList<TMXObjectGroup> tmxObjectGroups = this.mTMXTiledMap
.getTMXObjectGroups();
final ArrayList<TMXObject> tmxObjects = tmxObjectGroups.get(
tmxObjectGroups.size() - 1).getTMXObjects();
tmxObjects.get(tmxObjects.size() - 1).setmPolyLines(v2);
} else {
throw new TMXParseException("Unexpected start tag: '" + pLocalName
+ "'.");
}
}
@Override
public void characters(final char[] pCharacters, final int pStart,
final int pLength) throws SAXException {
this.mStringBuilder.append(pCharacters, pStart, pLength);
}
@Override
public void endElement(final String pUri, final String pLocalName,
final String pQualifiedName) throws SAXException {
if (pLocalName.equals(TMXConstants.TAG_MAP)) {
this.mInMap = false;
} else if (pLocalName.equals(TMXConstants.TAG_TILESET)) {
this.mInTileset = false;
} else if (pLocalName.equals(TMXConstants.TAG_IMAGE)) {
this.mInImage = false;
} else if (pLocalName.equals(TMXConstants.TAG_TILE)) {
this.mInTile = false;
} else if (pLocalName.equals(TMXConstants.TAG_PROPERTIES)) {
this.mInProperties = false;
} else if (pLocalName.equals(TMXConstants.TAG_PROPERTY)) {
this.mInProperty = false;
} else if (pLocalName.equals(TMXConstants.TAG_LAYER)) {
this.mInLayer = false;
} else if (pLocalName.equals(TMXConstants.TAG_DATA)) {
final boolean binarySaved = this.mDataCompression != null
&& this.mDataEncoding != null;
if (binarySaved) {
final ArrayList<TMXLayer> tmxLayers = this.mTMXTiledMap
.getTMXLayers();
try {
tmxLayers.get(tmxLayers.size() - 1)
.initializeTMXTilesFromDataString(
this.mStringBuilder.toString().trim(),
this.mDataEncoding, this.mDataCompression,
this.mTMXTilePropertyListener);
} catch (final IOException e) {
Debug.e(e);
}
this.mDataCompression = null;
this.mDataEncoding = null;
}
this.mInData = false;
} else if (pLocalName.equals(TMXConstants.TAG_OBJECTGROUP)) {
this.mInObjectGroup = false;
} else if (pLocalName.equals(TMXConstants.TAG_OBJECT)) {
this.mInObject = false;
} else if (pLocalName.equals(TMXConstants.TAG_OBJECT_POLYLINE)) {
this.mInPolyLine = false;
} else {
throw new TMXParseException("Unexpected end tag: '" + pLocalName
+ "'.");
}
/* Reset the StringBuilder. */
this.mStringBuilder.setLength(0);
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}