OSDN Git Service

af8a623787208b8b9fedf335e34b4c0daddc35f1
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / maps / tiled / AtlasTmxMapLoader.java
1
2 package com.badlogic.gdx.maps.tiled;
3
4 import java.io.ByteArrayInputStream;
5 import java.io.IOException;
6 import java.util.StringTokenizer;
7 import java.util.zip.DataFormatException;
8 import java.util.zip.GZIPInputStream;
9 import java.util.zip.Inflater;
10
11 import com.badlogic.gdx.assets.AssetDescriptor;
12 import com.badlogic.gdx.assets.AssetLoaderParameters;
13 import com.badlogic.gdx.assets.AssetManager;
14 import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
15 import com.badlogic.gdx.assets.loaders.FileHandleResolver;
16 import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
17 import com.badlogic.gdx.files.FileHandle;
18 import com.badlogic.gdx.graphics.Texture;
19 import com.badlogic.gdx.graphics.Texture.TextureFilter;
20 import com.badlogic.gdx.graphics.g2d.TextureAtlas;
21 import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
22 import com.badlogic.gdx.maps.MapLayer;
23 import com.badlogic.gdx.maps.MapObject;
24 import com.badlogic.gdx.maps.MapProperties;
25 import com.badlogic.gdx.maps.objects.EllipseMapObject;
26 import com.badlogic.gdx.maps.objects.PolygonMapObject;
27 import com.badlogic.gdx.maps.objects.PolylineMapObject;
28 import com.badlogic.gdx.maps.objects.RectangleMapObject;
29 import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
30 import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile;
31 import com.badlogic.gdx.math.Polygon;
32 import com.badlogic.gdx.math.Polyline;
33 import com.badlogic.gdx.utils.Array;
34 import com.badlogic.gdx.utils.Base64Coder;
35 import com.badlogic.gdx.utils.GdxRuntimeException;
36 import com.badlogic.gdx.utils.ObjectMap;
37 import com.badlogic.gdx.utils.XmlReader;
38 import com.badlogic.gdx.utils.XmlReader.Element;
39
40 /** A TiledMap Loader which loads tiles from a TextureAtlas instead of separate images.
41  * 
42  * It requires a map-level property called 'atlas' with its value being the relative path to the TextureAtlas. The atlas must have
43  * in it indexed regions named after the tilesets used in the map. The indexes shall be local to the tileset (not the global id).
44  * Strip whitespace and rotation should not be used when creating the atlas.
45  * 
46  * @author Justin Shapcott
47  * @author Manuel Bua */
48 public class AtlasTmxMapLoader extends AsynchronousAssetLoader<TiledMap, AtlasTmxMapLoader.AtlasTiledMapLoaderParameters> {
49
50         public static class AtlasTiledMapLoaderParameters extends AssetLoaderParameters<TiledMap> {
51                 /** Whether to load the map for a y-up coordinate system */
52                 public boolean yUp = true;
53
54                 /** force texture filters? **/
55                 public boolean forceTextureFilters = false;
56
57                 /** The TextureFilter to use for minification, if forceTextureFilter is enabled **/
58                 public TextureFilter textureMinFilter = TextureFilter.Nearest;
59
60                 /** The TextureFilter to use for magnification, if forceTextureFilter is enabled **/
61                 public TextureFilter textureMagFilter = TextureFilter.Nearest;
62         }
63
64         protected static final int FLAG_FLIP_HORIZONTALLY = 0x80000000;
65         protected static final int FLAG_FLIP_VERTICALLY = 0x40000000;
66         protected static final int FLAG_FLIP_DIAGONALLY = 0x20000000;
67         protected static final int MASK_CLEAR = 0xE0000000;
68
69         protected XmlReader xml = new XmlReader();
70         protected Element root;
71         protected boolean yUp;
72
73         protected int mapWidthInPixels;
74         protected int mapHeightInPixels;
75
76         protected TiledMap map;
77         protected Array<Texture> trackedTextures = new Array<Texture>();
78
79         private interface AtlasResolver {
80
81                 public TextureAtlas getAtlas (String name);
82
83                 public static class DirectAtlasResolver implements AtlasResolver {
84
85                         private final ObjectMap<String, TextureAtlas> atlases;
86
87                         public DirectAtlasResolver (ObjectMap<String, TextureAtlas> atlases) {
88                                 this.atlases = atlases;
89                         }
90
91                         @Override
92                         public TextureAtlas getAtlas (String name) {
93                                 return atlases.get(name);
94                         }
95
96                 }
97
98                 public static class AssetManagerAtlasResolver implements AtlasResolver {
99                         private final AssetManager assetManager;
100
101                         public AssetManagerAtlasResolver (AssetManager assetManager) {
102                                 this.assetManager = assetManager;
103                         }
104
105                         @Override
106                         public TextureAtlas getAtlas (String name) {
107                                 return assetManager.get(name, TextureAtlas.class);
108                         }
109                 }
110         }
111
112         public AtlasTmxMapLoader () {
113                 super(new InternalFileHandleResolver());
114         }
115
116         public AtlasTmxMapLoader (FileHandleResolver resolver) {
117                 super(resolver);
118         }
119
120         public TiledMap load (String fileName) {
121                 return load(fileName, new AtlasTiledMapLoaderParameters());
122         }
123
124         @Override
125         public Array<AssetDescriptor> getDependencies (String fileName, FileHandle tmxFile, AtlasTiledMapLoaderParameters parameter) {
126                 Array<AssetDescriptor> dependencies = new Array<AssetDescriptor>();
127                 try {
128                         root = xml.parse(tmxFile);
129
130                         Element properties = root.getChildByName("properties");
131                         if (properties != null) {
132                                 for (Element property : properties.getChildrenByName("property")) {
133                                         String name = property.getAttribute("name");
134                                         String value = property.getAttribute("value");
135                                         if (name.startsWith("atlas")) {
136                                                 FileHandle atlasHandle = getRelativeFileHandle(tmxFile, value);
137                                                 dependencies.add(new AssetDescriptor(atlasHandle, TextureAtlas.class));
138                                         }
139                                 }
140                         }
141                 } catch (IOException e) {
142                         throw new GdxRuntimeException("Unable to parse .tmx file.");
143                 }
144                 return dependencies;
145         }
146
147         public TiledMap load (String fileName, AtlasTiledMapLoaderParameters parameter) {
148                 try {
149                         if (parameter != null) {
150                                 yUp = parameter.yUp;
151                         } else {
152                                 yUp = true;
153                         }
154
155                         FileHandle tmxFile = resolve(fileName);
156                         root = xml.parse(tmxFile);
157                         ObjectMap<String, TextureAtlas> atlases = new ObjectMap<String, TextureAtlas>();
158                         FileHandle atlasFile = loadAtlas(root, tmxFile);
159                         if (atlasFile == null) {
160                                 throw new GdxRuntimeException("Couldn't load atlas");
161                         }
162
163                         TextureAtlas atlas = new TextureAtlas(atlasFile);
164                         atlases.put(atlasFile.path(), atlas);
165
166                         AtlasResolver.DirectAtlasResolver atlasResolver = new AtlasResolver.DirectAtlasResolver(atlases);
167                         TiledMap map = loadMap(root, tmxFile, atlasResolver, parameter);
168                         map.setOwnedResources(atlases.values().toArray());
169                         setTextureFilters(parameter.textureMinFilter, parameter.textureMagFilter);
170
171                         return map;
172                 } catch (IOException e) {
173                         throw new GdxRuntimeException("Couldn't load tilemap '" + fileName + "'", e);
174                 }
175         }
176
177         protected FileHandle loadAtlas (Element root, FileHandle tmxFile) throws IOException {
178                 Element e = root.getChildByName("properties");
179
180                 if (e != null) {
181                         for (Element property : e.getChildrenByName("property")) {
182                                 String name = property.getAttribute("name", null);
183                                 String value = property.getAttribute("value", null);
184                                 if (name.equals("atlas")) {
185                                         if (value == null) {
186                                                 value = property.getText();
187                                         }
188
189                                         if (value == null || value.length() == 0) {
190                                                 // keep trying until there are no more atlas properties
191                                                 continue;
192                                         }
193
194                                         return getRelativeFileHandle(tmxFile, value);
195                                 }
196                         }
197                 }
198
199                 return null;
200         }
201
202         private void setTextureFilters (TextureFilter min, TextureFilter mag) {
203                 for (Texture texture : trackedTextures) {
204                         texture.setFilter(min, mag);
205                 }
206         }
207
208         @Override
209         public void loadAsync (AssetManager manager, String fileName, FileHandle tmxFile, AtlasTiledMapLoaderParameters parameter) {
210                 map = null;
211
212                 if (parameter != null) {
213                         yUp = parameter.yUp;
214                 } else {
215                         yUp = true;
216                 }
217
218                 try {
219                         map = loadMap(root, tmxFile, new AtlasResolver.AssetManagerAtlasResolver(manager), parameter);
220                 } catch (Exception e) {
221                         throw new GdxRuntimeException("Couldn't load tilemap '" + fileName + "'", e);
222                 }
223         }
224
225         @Override
226         public TiledMap loadSync (AssetManager manager, String fileName, FileHandle file, AtlasTiledMapLoaderParameters parameter) {
227                 if (parameter != null) {
228                         setTextureFilters(parameter.textureMinFilter, parameter.textureMagFilter);
229                 }
230
231                 return map;
232         }
233
234         protected TiledMap loadMap (Element root, FileHandle tmxFile, AtlasResolver resolver, AtlasTiledMapLoaderParameters parameter) {
235                 TiledMap map = new TiledMap();
236
237                 String mapOrientation = root.getAttribute("orientation", null);
238                 int mapWidth = root.getIntAttribute("width", 0);
239                 int mapHeight = root.getIntAttribute("height", 0);
240                 int tileWidth = root.getIntAttribute("tilewidth", 0);
241                 int tileHeight = root.getIntAttribute("tileheight", 0);
242                 String mapBackgroundColor = root.getAttribute("backgroundcolor", null);
243
244                 MapProperties mapProperties = map.getProperties();
245                 if (mapOrientation != null) {
246                         mapProperties.put("orientation", mapOrientation);
247                 }
248                 mapProperties.put("width", mapWidth);
249                 mapProperties.put("height", mapHeight);
250                 mapProperties.put("tilewidth", tileWidth);
251                 mapProperties.put("tileheight", tileHeight);
252                 if (mapBackgroundColor != null) {
253                         mapProperties.put("backgroundcolor", mapBackgroundColor);
254                 }
255                 mapWidthInPixels = mapWidth * tileWidth;
256                 mapHeightInPixels = mapHeight * tileHeight;
257
258                 for (int i = 0, j = root.getChildCount(); i < j; i++) {
259                         Element element = root.getChild(i);
260                         String elementName = element.getName();
261                         if (elementName.equals("properties")) {
262                                 loadProperties(map.getProperties(), element);
263                         } else if (elementName.equals("tileset")) {
264                                 loadTileset(map, element, tmxFile, resolver, parameter);
265                         } else if (elementName.equals("layer")) {
266                                 loadTileLayer(map, element);
267                         } else if (elementName.equals("objectgroup")) {
268                                 loadObjectGroup(map, element);
269                         }
270                 }
271                 return map;
272         }
273
274         protected void loadTileset (TiledMap map, Element element, FileHandle tmxFile, AtlasResolver resolver,
275                 AtlasTiledMapLoaderParameters parameter) {
276                 if (element.getName().equals("tileset")) {
277                         String name = element.get("name", null);
278                         int firstgid = element.getIntAttribute("firstgid", 1);
279                         int tilewidth = element.getIntAttribute("tilewidth", 0);
280                         int tileheight = element.getIntAttribute("tileheight", 0);
281                         int spacing = element.getIntAttribute("spacing", 0);
282                         int margin = element.getIntAttribute("margin", 0);
283                         String source = element.getAttribute("source", null);
284
285                         String imageSource = "";
286                         int imageWidth = 0, imageHeight = 0;
287
288                         FileHandle image = null;
289                         if (source != null) {
290                                 FileHandle tsx = getRelativeFileHandle(tmxFile, source);
291                                 try {
292                                         element = xml.parse(tsx);
293                                         name = element.get("name", null);
294                                         tilewidth = element.getIntAttribute("tilewidth", 0);
295                                         tileheight = element.getIntAttribute("tileheight", 0);
296                                         spacing = element.getIntAttribute("spacing", 0);
297                                         margin = element.getIntAttribute("margin", 0);
298                                         imageSource = element.getChildByName("image").getAttribute("source");
299                                         imageWidth = element.getChildByName("image").getIntAttribute("width", 0);
300                                         imageHeight = element.getChildByName("image").getIntAttribute("height", 0);
301                                 } catch (IOException e) {
302                                         throw new GdxRuntimeException("Error parsing external tileset.");
303                                 }
304                         } else {
305                                 imageSource = element.getChildByName("image").getAttribute("source");
306                                 imageWidth = element.getChildByName("image").getIntAttribute("width", 0);
307                                 imageHeight = element.getChildByName("image").getIntAttribute("height", 0);
308                         }
309
310                         if (!map.getProperties().containsKey("atlas")) {
311                                 throw new GdxRuntimeException("The map is missing the 'atlas' property");
312                         }
313
314                         // get the TextureAtlas for this tileset
315                         FileHandle atlasHandle = getRelativeFileHandle(tmxFile, map.getProperties().get("atlas", String.class));
316                         atlasHandle = resolve(atlasHandle.path());
317                         TextureAtlas atlas = resolver.getAtlas(atlasHandle.path());
318                         String regionsName = atlasHandle.nameWithoutExtension();
319
320                         if (parameter != null && parameter.forceTextureFilters) {
321                                 for (Texture texture : atlas.getTextures()) {
322                                         trackedTextures.add(texture);
323                                 }
324                         }
325
326                         TiledMapTileSet tileset = new TiledMapTileSet();
327                         MapProperties props = tileset.getProperties();
328                         tileset.setName(name);
329                         props.put("firstgid", firstgid);
330                         props.put("imagesource", imageSource);
331                         props.put("imagewidth", imageWidth);
332                         props.put("imageheight", imageHeight);
333                         props.put("tilewidth", tilewidth);
334                         props.put("tileheight", tileheight);
335                         props.put("margin", margin);
336                         props.put("spacing", spacing);
337
338                         Array<AtlasRegion> regions = atlas.findRegions(regionsName);
339                         for (AtlasRegion region : regions) {
340                                 // handle unused tile ids
341                                 if (region != null) {
342                                         StaticTiledMapTile tile = new StaticTiledMapTile(region);
343
344                                         if (!yUp) {
345                                                 region.flip(false, true);
346                                         }
347
348                                         int tileid = firstgid + region.index;
349                                         tile.setId(tileid);
350                                         tileset.putTile(tileid, tile);
351                                 }
352                         }
353
354                         Array<Element> tileElements = element.getChildrenByName("tile");
355
356                         for (Element tileElement : tileElements) {
357                                 int localtid = tileElement.getIntAttribute("id", 0);
358                                 TiledMapTile tile = tileset.getTile(firstgid + localtid);
359                                 if (tile != null) {
360                                         String terrain = tileElement.getAttribute("terrain", null);
361                                         if (terrain != null) {
362                                                 tile.getProperties().put("terrain", terrain);
363                                         }
364                                         String probability = tileElement.getAttribute("probability", null);
365                                         if (probability != null) {
366                                                 tile.getProperties().put("probability", probability);
367                                         }
368                                         Element properties = tileElement.getChildByName("properties");
369                                         if (properties != null) {
370                                                 loadProperties(tile.getProperties(), properties);
371                                         }
372                                 }
373                         }
374
375                         Element properties = element.getChildByName("properties");
376                         if (properties != null) {
377                                 loadProperties(tileset.getProperties(), properties);
378                         }
379                         map.getTileSets().addTileSet(tileset);
380                 }
381         }
382
383         protected void loadTileLayer (TiledMap map, Element element) {
384                 if (element.getName().equals("layer")) {
385                         String name = element.getAttribute("name", null);
386                         int width = element.getIntAttribute("width", 0);
387                         int height = element.getIntAttribute("height", 0);
388                         int tileWidth = element.getParent().getIntAttribute("tilewidth", 0);
389                         int tileHeight = element.getParent().getIntAttribute("tileheight", 0);
390                         boolean visible = element.getIntAttribute("visible", 1) == 1;
391                         float opacity = element.getFloatAttribute("opacity", 1.0f);
392                         TiledMapTileLayer layer = new TiledMapTileLayer(width, height, tileWidth, tileHeight);
393                         layer.setVisible(visible);
394                         layer.setOpacity(opacity);
395                         layer.setName(name);
396
397                         TiledMapTileSets tilesets = map.getTileSets();
398
399                         Element data = element.getChildByName("data");
400                         String encoding = data.getAttribute("encoding", null);
401                         String compression = data.getAttribute("compression", null);
402                         if (encoding == null) { // no 'encoding' attribute means that the encoding is XML
403                                 throw new GdxRuntimeException("Unsupported encoding (XML) for TMX Layer Data");
404                         }
405                         if (encoding.equals("csv")) {
406                                 String[] array = data.getText().split(",");
407                                 for (int y = 0; y < height; y++) {
408                                         for (int x = 0; x < width; x++) {
409                                                 int id = (int)Long.parseLong(array[y * width + x].trim());
410
411                                                 final boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0);
412                                                 final boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0);
413                                                 final boolean flipDiagonally = ((id & FLAG_FLIP_DIAGONALLY) != 0);
414
415                                                 id = id & ~MASK_CLEAR;
416
417                                                 tilesets.getTile(id);
418                                                 TiledMapTile tile = tilesets.getTile(id);
419                                                 if (tile != null) {
420                                                         Cell cell = createTileLayerCell(flipHorizontally, flipVertically, flipDiagonally);
421                                                         cell.setTile(tile);
422                                                         layer.setCell(x, yUp ? height - 1 - y : y, cell);
423                                                 }
424                                         }
425                                 }
426                         } else {
427                                 if (encoding.equals("base64")) {
428                                         byte[] bytes = Base64Coder.decode(data.getText());
429                                         if (compression == null) {
430                                                 int read = 0;
431                                                 for (int y = 0; y < height; y++) {
432                                                         for (int x = 0; x < width; x++) {
433
434                                                                 int id = unsignedByteToInt(bytes[read++]) | unsignedByteToInt(bytes[read++]) << 8
435                                                                         | unsignedByteToInt(bytes[read++]) << 16 | unsignedByteToInt(bytes[read++]) << 24;
436
437                                                                 final boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0);
438                                                                 final boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0);
439                                                                 final boolean flipDiagonally = ((id & FLAG_FLIP_DIAGONALLY) != 0);
440
441                                                                 id = id & ~MASK_CLEAR;
442
443                                                                 tilesets.getTile(id);
444                                                                 TiledMapTile tile = tilesets.getTile(id);
445                                                                 if (tile != null) {
446                                                                         Cell cell = createTileLayerCell(flipHorizontally, flipVertically, flipDiagonally);
447                                                                         cell.setTile(tile);
448                                                                         layer.setCell(x, yUp ? height - 1 - y : y, cell);
449                                                                 }
450                                                         }
451                                                 }
452                                         } else if (compression.equals("gzip")) {
453                                                 GZIPInputStream GZIS = null;
454                                                 try {
455                                                         GZIS = new GZIPInputStream(new ByteArrayInputStream(bytes), bytes.length);
456                                                 } catch (IOException e) {
457                                                         throw new GdxRuntimeException("Error Reading TMX Layer Data - IOException: " + e.getMessage());
458                                                 }
459
460                                                 byte[] temp = new byte[4];
461                                                 for (int y = 0; y < height; y++) {
462                                                         for (int x = 0; x < width; x++) {
463                                                                 try {
464                                                                         GZIS.read(temp, 0, 4);
465                                                                         int id = unsignedByteToInt(temp[0]) | unsignedByteToInt(temp[1]) << 8
466                                                                                 | unsignedByteToInt(temp[2]) << 16 | unsignedByteToInt(temp[3]) << 24;
467
468                                                                         final boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0);
469                                                                         final boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0);
470                                                                         final boolean flipDiagonally = ((id & FLAG_FLIP_DIAGONALLY) != 0);
471
472                                                                         id = id & ~MASK_CLEAR;
473
474                                                                         tilesets.getTile(id);
475                                                                         TiledMapTile tile = tilesets.getTile(id);
476                                                                         if (tile != null) {
477                                                                                 Cell cell = createTileLayerCell(flipHorizontally, flipVertically, flipDiagonally);
478                                                                                 cell.setTile(tile);
479                                                                                 layer.setCell(x, yUp ? height - 1 - y : y, cell);
480                                                                         }
481                                                                 } catch (IOException e) {
482                                                                         throw new GdxRuntimeException("Error Reading TMX Layer Data.", e);
483                                                                 }
484                                                         }
485                                                 }
486                                         } else if (compression.equals("zlib")) {
487                                                 Inflater zlib = new Inflater();
488
489                                                 byte[] temp = new byte[4];
490
491                                                 zlib.setInput(bytes, 0, bytes.length);
492
493                                                 for (int y = 0; y < height; y++) {
494                                                         for (int x = 0; x < width; x++) {
495                                                                 try {
496                                                                         zlib.inflate(temp, 0, 4);
497                                                                         int id = unsignedByteToInt(temp[0]) | unsignedByteToInt(temp[1]) << 8
498                                                                                 | unsignedByteToInt(temp[2]) << 16 | unsignedByteToInt(temp[3]) << 24;
499
500                                                                         final boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0);
501                                                                         final boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0);
502                                                                         final boolean flipDiagonally = ((id & FLAG_FLIP_DIAGONALLY) != 0);
503
504                                                                         id = id & ~MASK_CLEAR;
505
506                                                                         tilesets.getTile(id);
507                                                                         TiledMapTile tile = tilesets.getTile(id);
508                                                                         if (tile != null) {
509                                                                                 Cell cell = createTileLayerCell(flipHorizontally, flipVertically, flipDiagonally);
510                                                                                 cell.setTile(tile);
511                                                                                 layer.setCell(x, yUp ? height - 1 - y : y, cell);
512                                                                         }
513
514                                                                 } catch (DataFormatException e) {
515                                                                         throw new GdxRuntimeException("Error Reading TMX Layer Data.", e);
516                                                                 }
517                                                         }
518                                                 }
519                                         }
520                                 } else {
521                                         // any other value of 'encoding' is one we're not aware of, probably a feature of a future version of Tiled
522                                         // or another editor
523                                         throw new GdxRuntimeException("Unrecognised encoding (" + encoding + ") for TMX Layer Data");
524                                 }
525                         }
526                         Element properties = element.getChildByName("properties");
527                         if (properties != null) {
528                                 loadProperties(layer.getProperties(), properties);
529                         }
530                         map.getLayers().add(layer);
531                 }
532         }
533
534         protected void loadObjectGroup (TiledMap map, Element element) {
535                 if (element.getName().equals("objectgroup")) {
536                         String name = element.getAttribute("name", null);
537                         MapLayer layer = new MapLayer();
538                         layer.setName(name);
539                         Element properties = element.getChildByName("properties");
540                         if (properties != null) {
541                                 loadProperties(layer.getProperties(), properties);
542                         }
543
544                         for (Element objectElement : element.getChildrenByName("object")) {
545                                 loadObject(layer, objectElement);
546                         }
547
548                         map.getLayers().add(layer);
549                 }
550         }
551
552         protected void loadObject (MapLayer layer, Element element) {
553                 if (element.getName().equals("object")) {
554                         MapObject object = null;
555
556                         int x = element.getIntAttribute("x", 0);
557                         int y = (yUp ? mapHeightInPixels - element.getIntAttribute("y", 0) : element.getIntAttribute("y", 0));
558
559                         int width = element.getIntAttribute("width", 0);
560                         int height = element.getIntAttribute("height", 0);
561
562                         if (element.getChildCount() > 0) {
563                                 Element child = null;
564                                 if ((child = element.getChildByName("polygon")) != null) {
565                                         String[] points = child.getAttribute("points").split(" ");
566                                         float[] vertices = new float[points.length * 2];
567                                         for (int i = 0; i < points.length; i++) {
568                                                 String[] point = points[i].split(",");
569                                                 vertices[i * 2] = Integer.parseInt(point[0]);
570                                                 vertices[i * 2 + 1] = Integer.parseInt(point[1]);
571                                                 if (yUp) {
572                                                         vertices[i * 2 + 1] *= -1;
573                                                 }
574                                         }
575                                         Polygon polygon = new Polygon(vertices);
576                                         polygon.setPosition(x, y);
577                                         object = new PolygonMapObject(polygon);
578                                 } else if ((child = element.getChildByName("polyline")) != null) {
579                                         String[] points = child.getAttribute("points").split(" ");
580                                         float[] vertices = new float[points.length * 2];
581                                         for (int i = 0; i < points.length; i++) {
582                                                 String[] point = points[i].split(",");
583                                                 vertices[i * 2] = Integer.parseInt(point[0]);
584                                                 vertices[i * 2 + 1] = Integer.parseInt(point[1]);
585                                                 if (yUp) {
586                                                         vertices[i * 2 + 1] *= -1;
587                                                 }
588                                         }
589                                         Polyline polyline = new Polyline(vertices);
590                                         polyline.setPosition(x, y);
591                                         object = new PolylineMapObject(polyline);
592                                 } else if ((child = element.getChildByName("ellipse")) != null) {
593                                         object = new EllipseMapObject(x, yUp ? y - height : y, width, height);
594                                 }
595                         }
596                         if (object == null) {
597                                 object = new RectangleMapObject(x, yUp ? y - height : y, width, height);
598                         }
599                         object.setName(element.getAttribute("name", null));
600                         String type = element.getAttribute("type", null);
601                         if (type != null) {
602                                 object.getProperties().put("type", type);
603                         }
604                         int gid = element.getIntAttribute("gid", -1);
605                         if (gid != -1) {
606                                 object.getProperties().put("gid", gid);
607                         }
608                         object.getProperties().put("x", x);
609                         object.getProperties().put("y", yUp ? y - height : y);
610                         object.setVisible(element.getIntAttribute("visible", 1) == 1);
611                         Element properties = element.getChildByName("properties");
612                         if (properties != null) {
613                                 loadProperties(object.getProperties(), properties);
614                         }
615                         layer.getObjects().add(object);
616                 }
617         }
618
619         protected void loadProperties (MapProperties properties, Element element) {
620                 if (element.getName().equals("properties")) {
621                         for (Element property : element.getChildrenByName("property")) {
622                                 String name = property.getAttribute("name", null);
623                                 String value = property.getAttribute("value", null);
624                                 if (value == null) {
625                                         value = property.getText();
626                                 }
627                                 properties.put(name, value);
628                         }
629                 }
630         }
631
632         protected Cell createTileLayerCell (boolean flipHorizontally, boolean flipVertically, boolean flipDiagonally) {
633                 Cell cell = new Cell();
634                 if (flipDiagonally) {
635                         if (flipHorizontally && flipVertically) {
636                                 cell.setFlipHorizontally(true);
637                                 cell.setRotation(yUp ? Cell.ROTATE_270 : Cell.ROTATE_90);
638                         } else if (flipHorizontally) {
639                                 cell.setRotation(yUp ? Cell.ROTATE_270 : Cell.ROTATE_90);
640                         } else if (flipVertically) {
641                                 cell.setRotation(yUp ? Cell.ROTATE_90 : Cell.ROTATE_270);
642                         } else {
643                                 cell.setFlipVertically(true);
644                                 cell.setRotation(yUp ? Cell.ROTATE_270 : Cell.ROTATE_90);
645                         }
646                 } else {
647                         cell.setFlipHorizontally(flipHorizontally);
648                         cell.setFlipVertically(flipVertically);
649                 }
650                 return cell;
651         }
652
653         public static FileHandle getRelativeFileHandle (FileHandle file, String path) {
654                 StringTokenizer tokenizer = new StringTokenizer(path, "\\/");
655                 FileHandle result = file.parent();
656                 while (tokenizer.hasMoreElements()) {
657                         String token = tokenizer.nextToken();
658                         if (token.equals(".."))
659                                 result = result.parent();
660                         else {
661                                 result = result.child(token);
662                         }
663                 }
664                 return result;
665         }
666
667         protected static int unsignedByteToInt (byte b) {
668                 return (int)b & 0xFF;
669         }
670 }