OSDN Git Service

Merge remote-tracking branch 'origin/master'
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / maps / tiled / TideMapLoader.java
1 package com.badlogic.gdx.maps.tiled;
2
3 import java.io.IOException;
4 import java.util.StringTokenizer;
5
6 import com.badlogic.gdx.assets.AssetDescriptor;
7 import com.badlogic.gdx.assets.AssetLoaderParameters;
8 import com.badlogic.gdx.assets.AssetManager;
9 import com.badlogic.gdx.assets.loaders.FileHandleResolver;
10 import com.badlogic.gdx.assets.loaders.SynchronousAssetLoader;
11 import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
12 import com.badlogic.gdx.files.FileHandle;
13 import com.badlogic.gdx.graphics.Texture;
14 import com.badlogic.gdx.graphics.g2d.TextureRegion;
15 import com.badlogic.gdx.maps.ImageResolver;
16 import com.badlogic.gdx.maps.MapProperties;
17 import com.badlogic.gdx.maps.ImageResolver.AssetManagerImageResolver;
18 import com.badlogic.gdx.maps.ImageResolver.DirectImageResolver;
19 import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile;
20 import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile;
21 import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
22 import com.badlogic.gdx.utils.Array;
23 import com.badlogic.gdx.utils.GdxRuntimeException;
24 import com.badlogic.gdx.utils.ObjectMap;
25 import com.badlogic.gdx.utils.XmlReader;
26 import com.badlogic.gdx.utils.XmlReader.Element;
27
28 public class TideMapLoader extends SynchronousAssetLoader<TiledMap, TideMapLoader.Parameters> {
29
30         public static class Parameters extends AssetLoaderParameters<TiledMap> {
31                 
32         }
33         
34         private XmlReader xml = new XmlReader();
35         private Element root;
36         
37         public TideMapLoader() {
38                 super(new InternalFileHandleResolver());
39         }
40         
41         public TideMapLoader (FileHandleResolver resolver) {
42                 super(resolver);
43         }
44
45         public TiledMap load (String fileName) {
46                 try {
47                         FileHandle tideFile = resolve(fileName);
48                         root = xml.parse(tideFile);
49                         ObjectMap<String, Texture> textures = new ObjectMap<String, Texture>();
50                         for(FileHandle textureFile: loadTileSheets(root, tideFile)) {
51                                 textures.put(textureFile.path(), new Texture(textureFile));
52                         }
53                         DirectImageResolver imageResolver = new DirectImageResolver(textures);
54                         TiledMap map = loadMap(root, tideFile, imageResolver);
55                         map.setOwnedTextures(textures.values().toArray());
56                         return map;
57                 } catch(IOException e) {
58                         throw new GdxRuntimeException("Couldn't load tilemap '" + fileName + "'", e);
59                 }
60
61         }
62         
63         @Override
64         public TiledMap load (AssetManager assetManager, String fileName, Parameters parameter) {
65                 FileHandle tideFile = resolve(fileName);
66                 try {
67                         return loadMap(root, tideFile, new AssetManagerImageResolver(assetManager));
68                 } catch (Exception e) {
69                         throw new GdxRuntimeException("Couldn't load tilemap '" + fileName + "'", e);
70                 }
71         }
72
73         @Override
74         public Array<AssetDescriptor> getDependencies (String fileName, Parameters parameter) {
75                 Array<AssetDescriptor> dependencies = new Array<AssetDescriptor>();
76                 try {
77                         FileHandle tmxFile = resolve(fileName);
78                         root = xml.parse(tmxFile);
79                         for(FileHandle image: loadTileSheets(root, tmxFile)) {
80                                 dependencies.add(new AssetDescriptor(image.path(), Texture.class));
81                         }
82                         return dependencies;
83                 } catch (IOException e) {
84                         throw new GdxRuntimeException("Couldn't load tilemap '" + fileName + "'", e);
85                 }
86         }
87         
88         /**
89          * Loads the map data, given the XML root element and an {@link ImageResolver} used
90          * to return the tileset Textures
91          * @param root the XML root element 
92          * @param tmxFile the Filehandle of the tmx file
93          * @param imageResolver the {@link ImageResolver}
94          * @return the {@link TiledMap}
95          */
96         private TiledMap loadMap(Element root, FileHandle tmxFile, ImageResolver imageResolver) {
97                 TiledMap map = new TiledMap();
98                 Element properties = root.getChildByName("properties");
99                 if (properties != null) {
100                         loadProperties(map.getProperties(), properties);
101                 }
102                 Element tilesheets = root.getChildByName("TileSheets");
103                 for (Element tilesheet : tilesheets.getChildrenByName("TileSheet")) {
104                         loadTileSheet(map, tilesheet, tmxFile, imageResolver);
105                 }
106                 Element layers = root.getChildByName("Layers");
107                 for (Element layer : layers.getChildrenByName("Layer")) {
108                         loadLayer(map, layer);
109                 }
110                 return map;
111         }
112         
113         /**
114          * Loads the tilesets
115          * @param root the root XML element
116          * @return a list of filenames for images containing tiles
117          * @throws IOException 
118          */
119         private Array<FileHandle> loadTileSheets(Element root, FileHandle tideFile) throws IOException {
120                 Array<FileHandle> images = new Array<FileHandle>();
121                 Element tilesheets = root.getChildByName("TileSheets");
122                 for (Element tileset : tilesheets.getChildrenByName("TileSheet")) {
123                         Element imageSource = tileset.getChildByName("ImageSource");
124                         FileHandle image = getRelativeFileHandle(tideFile, imageSource.getText());
125                         images.add(image);
126                 }
127                 return images;
128         }
129         
130         private void loadTileSheet(TiledMap map, Element element, FileHandle tideFile, ImageResolver imageResolver) {
131                 if (element.getName().equals("TileSheet")) {
132                         String id = element.getAttribute("Id");
133                         String description = element.getChildByName("Description").getText();
134                         String imageSource = element.getChildByName("ImageSource").getText();
135                         
136                         Element alignment = element.getChildByName("Alignment");
137                         String sheetSize = alignment.getAttribute("SheetSize");
138                         String tileSize = alignment.getAttribute("TileSize");
139                         String margin = alignment.getAttribute("Margin");
140                         String spacing = alignment.getAttribute("Spacing");
141                         
142                         String[] sheetSizeParts = sheetSize.split(" x ");
143                         int sheetSizeX = Integer.parseInt(sheetSizeParts[0]);
144                         int sheetSizeY = Integer.parseInt(sheetSizeParts[1]);
145                         
146                         String[] tileSizeParts = tileSize.split(" x ");
147                         int tileSizeX = Integer.parseInt(tileSizeParts[0]);
148                         int tileSizeY = Integer.parseInt(tileSizeParts[1]);
149                         
150                         String[] marginParts = margin.split(" x ");
151                         int marginX = Integer.parseInt(marginParts[0]);
152                         int marginY = Integer.parseInt(marginParts[1]);
153
154                         String[] spacingParts = margin.split(" x ");
155                         int spacingX = Integer.parseInt(spacingParts[0]);
156                         int spacingY = Integer.parseInt(spacingParts[1]);
157
158                         FileHandle image = getRelativeFileHandle(tideFile, imageSource);
159                         TextureRegion texture = imageResolver.getImage(image.path());
160                         
161                         // TODO: Actually load the tilesheet
162                         // Need to make global ids as Tide doesn't have global ids.
163                         TiledMapTileSets tilesets = map.getTileSets();
164                         int firstgid = 1;
165                         for (TiledMapTileSet tileset : tilesets) {
166                                 firstgid += tileset.size();
167                         }
168                         
169                         TiledMapTileSet tileset = new TiledMapTileSet();
170                         tileset.setName(id);
171                         tileset.getProperties().put("firstgid", firstgid);
172                         int gid = firstgid;
173                         
174                         int stopWidth = texture.getRegionWidth() - tileSizeX;
175                         int stopHeight = texture.getRegionHeight() - tileSizeY;
176                         
177                         for (int y = marginY; y <= stopHeight; y += tileSizeY + spacingY) {
178                                 for (int x = marginX; x <= stopWidth; x += tileSizeX + spacingX) {
179                                         TiledMapTile tile = new StaticTiledMapTile(new TextureRegion(texture, x, y, tileSizeX, tileSizeY));
180                                         tile.setId(gid);
181                                         tileset.putTile(gid++, tile);
182                                 }
183                         }
184                         
185                         Element properties = element.getChildByName("Properties");
186                         if (properties != null) {
187                                 loadProperties(tileset.getProperties(), properties);
188                         }
189                         
190                         tilesets.addTileSet(tileset);
191                 }
192         }
193         
194         private void loadLayer(TiledMap map, Element element) {
195                 if (element.getName().equals("Layer")) {
196                         String id = element.getAttribute("Id");
197                         String visible = element.getAttribute("Visible");
198                         
199                         Element dimensions = element.getChildByName("Dimensions");
200                         String layerSize = dimensions.getAttribute("LayerSize");
201                         String tileSize = dimensions.getAttribute("TileSize");
202                         
203                         String[] layerSizeParts = layerSize.split(" x ");
204                         int layerSizeX = Integer.parseInt(layerSizeParts[0]);
205                         int layerSizeY = Integer.parseInt(layerSizeParts[1]);
206                         
207                         String[] tileSizeParts = tileSize.split(" x ");
208                         int tileSizeX = Integer.parseInt(tileSizeParts[0]);
209                         int tileSizeY = Integer.parseInt(tileSizeParts[1]);
210                         
211                         TiledMapTileLayer layer = new TiledMapTileLayer(layerSizeX, layerSizeY, tileSizeX, tileSizeY);
212                         Element tileArray = element.getChildByName("TileArray");
213                         Array<Element> rows = tileArray.getChildrenByName("Row");
214                         TiledMapTileSets tilesets = map.getTileSets();
215                         TiledMapTileSet currentTileSet = null;
216                         int firstgid = 0;
217                         int x, y;
218                         for (int row = 0, rowCount = rows.size; row < rowCount; row++) {
219                                 Element currentRow = rows.get(row);
220                                 y = rowCount -1 - row;
221                                 x = 0;
222                                 for (int child = 0, childCount = currentRow.getChildCount(); child < childCount; child++) {
223                                         Element currentChild = currentRow.getChild(child);
224                                         String name = currentChild.getName();
225                                         if (name.equals("TileSheet")) {
226                                                 currentTileSet = tilesets.getTileSet(currentChild.getAttribute("Ref"));
227                                                 firstgid = currentTileSet.getProperties().get("firstgid", Integer.class);
228                                         } else if (name.equals("Null")) {
229                                                 x += currentChild.getIntAttribute("Count");
230                                         } else if (name.equals("Static")) {
231                                                 Cell cell = new Cell();
232                                                 cell.setTile(currentTileSet.getTile(firstgid + currentChild.getIntAttribute("Index")));
233                                                 layer.setCell(x++, y, cell);
234                                         } else if (name.equals("Animated")) {
235                                                 // Create an AnimatedTile
236                                                 int interval = currentChild.getInt("Interval");
237                                                 Element frames = currentChild.getChildByName("Frames");
238                                                 Array<StaticTiledMapTile> frameTiles = new Array<StaticTiledMapTile>();
239                                                 for (int frameChild = 0, frameChildCount = frames.getChildCount(); frameChild < frameChildCount; frameChild++) {
240                                                         Element frame = frames.getChild(frameChild);
241                                                         String frameName = frame.getName();
242                                                         if (frameName.equals("TileSheet")) {
243                                                                 currentTileSet = tilesets.getTileSet(frame.getAttribute("Ref"));
244                                                                 firstgid = currentTileSet.getProperties().get("firstgid", Integer.class);
245                                                         } else if (frameName.equals("Static")) {
246                                                                 frameTiles.add((StaticTiledMapTile) currentTileSet.getTile(firstgid + frame.getIntAttribute("Index")));
247                                                         }
248                                                 }
249                                                 Cell cell = new Cell();
250                                                 cell.setTile(new AnimatedTiledMapTile(interval / 1000f, frameTiles));
251                                                 layer.setCell(x++, y, cell); //TODO: Reuse existing animated tiles
252                                         }
253                                 }
254                         }
255                         map.getLayers().add(layer);
256                 }
257         }
258         
259         private void loadProperties(MapProperties properties, Element element) {
260                 if (element.getName().equals("Properties")) {
261                         for (Element property : element.getChildrenByName("Property")) {
262                                 String key = property.getAttribute("Key", null);
263                                 String type = property.getAttribute("Type", null);
264                                 String value = property.getText();
265                                 
266                                 if (type.equals("Int32")) {
267                                         properties.put(key, Integer.parseInt(value));
268                                 } else if (type.equals("String")) {
269                                         properties.put(key, value);
270                                 } else if (type.equals("Boolean")) {
271                                         properties.put(key, value.equalsIgnoreCase("true"));
272                                 } else {
273                                         properties.put(key, value);                                     
274                                 }
275                         }
276                 }
277         }
278         
279         private static FileHandle getRelativeFileHandle(FileHandle file, String path) {
280                 StringTokenizer tokenizer = new StringTokenizer(path, "\\/");
281                 FileHandle result = file.parent();
282                 while (tokenizer.hasMoreElements()) {
283                         String token = tokenizer.nextToken();
284                         if (token.equals(".."))
285                                 result = result.parent();
286                         else {
287                                 result = result.child(token);
288                         }
289                 }
290                 return result;          
291         }
292
293 }