1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dishevelled.piccolo.tilemap.io.impl;
25
26 import java.awt.Image;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.InputStream;
31
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import javax.xml.parsers.SAXParserFactory;
36
37 import net.sf.stax.SAX2StAXAdaptor;
38 import net.sf.stax.StAXContentHandlerBase;
39 import net.sf.stax.StAXContext;
40 import net.sf.stax.StAXDelegationContext;
41
42 import org.dishevelled.piccolo.sprite.Animations;
43 import org.dishevelled.piccolo.sprite.Sprite;
44
45 import org.dishevelled.piccolo.tilemap.AbstractTileMap;
46 import org.dishevelled.piccolo.tilemap.SparseTileMap;
47
48 import org.xml.sax.XMLReader;
49 import org.xml.sax.Attributes;
50 import org.xml.sax.InputSource;
51 import org.xml.sax.SAXException;
52 import org.xml.sax.ContentHandler;
53
54
55
56
57
58
59
60
61 public class TmxTileMapReader
62 extends AbstractTileMapReader
63 {
64
65 private XMLReader xmlReader;
66
67
68
69
70
71 public TmxTileMapReader()
72 {
73 try
74 {
75 xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
76 }
77 catch (Exception e)
78 {
79
80 }
81 }
82
83
84 @Override
85 public AbstractTileMap read(final InputStream inputStream) throws IOException
86 {
87 if (inputStream == null)
88 {
89 throw new IllegalArgumentException ("inputStream must not be null");
90 }
91 InputSource inputSource = new InputSource(inputStream);
92 MapHandler mapHandler = new MapHandler();
93 ContentHandler contentHandler = new SAX2StAXAdaptor(mapHandler);
94 xmlReader.setContentHandler(contentHandler);
95 try
96 {
97 xmlReader.parse(inputSource);
98 }
99 catch (SAXException e)
100 {
101 throw new IOException("could not read input stream", e);
102 }
103 return mapHandler.getTileMap();
104 }
105
106
107
108
109 private static final class MapHandler
110 extends StAXContentHandlerBase
111 {
112 private long width;
113 private long height;
114 private double tileWidth;
115 private double tileHeight;
116 private SparseTileMap tileMap;
117 private List<Sprite> sprites;
118
119
120 private DataHandler dataHandler = new DataHandler();
121
122 private TilesetHandler tilesetHandler = new TilesetHandler();
123
124
125 @Override
126 public void startElement(final String nsURI,
127 final String localName,
128 final String qName,
129 final Attributes attrs,
130 final StAXDelegationContext dctx)
131 throws SAXException
132 {
133 if ("tileset".equals(qName))
134 {
135 dctx.delegate(tilesetHandler);
136 }
137 else if ("data".equals(qName))
138 {
139 dctx.delegate(dataHandler);
140 }
141 else if ("map".equals(qName))
142 {
143 width = Long.parseLong(attrs.getValue("width"));
144 height = Long.parseLong(attrs.getValue("height"));
145 tileWidth = Double.parseDouble(attrs.getValue("tilewidth"));
146 tileHeight = Double.parseDouble(attrs.getValue("tileheight"));
147 tileMap = new SparseTileMap(width, height, tileWidth, tileHeight);
148 }
149 }
150
151 @Override
152 public void endElement(final String nsURI,
153 final String localName,
154 final String qName,
155 final Object result,
156 final StAXContext context)
157 throws SAXException
158 {
159 if ("tileset".equals(qName))
160 {
161 sprites = (List<Sprite>) result;
162 }
163 }
164
165
166
167
168
169
170 SparseTileMap getTileMap()
171 {
172 return tileMap;
173 }
174
175
176
177
178 private class DataHandler
179 extends StAXContentHandlerBase
180 {
181 private long i;
182
183 @Override
184 public void startTree(final StAXContext ctx) throws SAXException
185 {
186 i = 0;
187 }
188
189 @Override
190 public void startElement(final String nsURI,
191 final String localName,
192 final String qName,
193 final Attributes attrs,
194 final StAXDelegationContext dctx)
195 throws SAXException
196 {
197 if ("tile".equals(qName))
198 {
199 int gid = Integer.parseInt(attrs.getValue("gid"));
200 if (gid > 0)
201 {
202 long x = i / width;
203 long y = i % height;
204 Sprite sprite = sprites.get(gid - 1);
205 tileMap.setTileXY(x, y, sprite);
206 }
207 i++;
208 }
209 }
210 }
211 }
212
213
214
215
216 private static final class TilesetHandler
217 extends StAXContentHandlerBase
218 {
219 private String source;
220 private int width;
221 private int height;
222 private int tileWidth;
223 private int tileHeight;
224
225 @Override
226 public void startElement(final String nsURI,
227 final String localName,
228 final String qName,
229 final Attributes attrs,
230 final StAXDelegationContext dctx)
231 throws SAXException
232 {
233 if ("image".equals(qName))
234 {
235 source = attrs.getValue("source");
236 width = Integer.parseInt(attrs.getValue("width"));
237 height = Integer.parseInt(attrs.getValue("height"));
238 }
239 else if ("tileset".equals(qName))
240 {
241 tileWidth = Integer.parseInt(attrs.getValue("tilewidth"));
242 tileHeight = Integer.parseInt(attrs.getValue("tileheight"));
243 }
244 }
245
246 @Override
247 public Object endTree(final StAXContext context)
248 throws SAXException
249 {
250
251 try
252 {
253 List<Image> tiles = Animations.createFrameList(new File(source), 0, 0, tileWidth, tileHeight, width / tileWidth);
254 List<Sprite> tileSprites = new ArrayList<Sprite>(tiles.size());
255 for (Image tile : tiles)
256 {
257 Sprite tileSprite = new Sprite(Animations.createAnimation(tile));
258 tileSprite.setWidth(tileWidth);
259 tileSprite.setHeight(tileHeight);
260 tileSprites.add(tileSprite);
261 }
262 return tileSprites;
263 }
264 catch (IOException e)
265 {
266 throw new SAXException("could not create tileset from source", e);
267 }
268 }
269 }
270 }