OSDN Git Service

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