Package arcmap :: Module mapio
[hide private]
[frames] | no frames]

Source Code for Module arcmap.mapio

  1  ################################################################################ 
  2  # Authors: Brian Schott (Sir Alaran) 
  3  # Copyright: Brian Schott (Sir Alaran) 
  4  # Date: Sep 29 2009 
  5  # License: 
  6  # 
  7  # This program is free software: you can redistribute it and/or modify 
  8  # it under the terms of the GNU General Public License as published by 
  9  # the Free Software Foundation, either version 3 of the License, or 
 10  # (at your option) any later version. 
 11  # 
 12  # This program is distributed in the hope that it will be useful, 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 15  # GNU General Public License for more details. 
 16  # 
 17  # You should have received a copy of the GNU General Public License 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 19  ################################################################################ 
 20   
 21   
 22  """ 
 23  File input and output for the TileMap class. 
 24  """ 
 25   
 26  import os.path 
 27  import xml.dom.minidom 
 28  import tilemap 
 29  import logging 
 30   
 31  import preferences 
 32  import tilemap 
 33  import shapes 
 34  import graphics 
 35  import datafiles 
 36   
 37  log = logging.getLogger("mapio") 
38 39 -class MapWriter:
40 - def __init__(self, fileName):
41 """ 42 Brief Description 43 @type fileName: string 44 @param fileName: Placeholder 45 """ 46 self.__fileName = fileName
47
48 - def getFileName(self):
49 return self.__fileName
50 51 @staticmethod
52 - def getWriter(fileName):
53 """ 54 Modify this function when adding a new output class 55 @type fileName: string 56 @param fileName: thre name of the file that the map will be saved to 57 """ 58 base, ext = os.path.splitext(fileName) 59 ext = str.upper(ext)[1:] 60 if ext == "XML": 61 return XMLMapWriter(fileName) 62 elif ext == "JSON": 63 return JSONMapWriter(fileName) 64 else: 65 raise Exception("No writer class for file type \"" + ext + "\"")
66
67 - def finish(self):
68 """ 69 Finish writing the map. 70 """ 71 raise Exception("MapWriter.finish is abstract")
72
73 - def writeInfo(width, height, tileSize, name, description):
74 """ 75 @type width: placeholder 76 @param width: placeholder 77 @type height: placeholder 78 @param height: placeholder 79 @type tileSize: placeholder 80 @param tileSize: placeholder 81 @type name: placeholder 82 @param name: placeholder 83 @type description: placeholder 84 @param description: placeholder 85 """ 86 raise Exception("MapWriter.writeInfo is abstract")
87
88 - def writeLayers(self, layers):
89 """ 90 Brief Description 91 @type layers: Layer[] 92 @param layers: Placeholder 93 """ 94 raise Exception("MapWriter.writeLayers is abstract")
95
96 - def writeShapes(self, shapes):
97 """ 98 Brief Description 99 @type shapes: Shape[] 100 @param shapes: Placeholder 101 """ 102 raise Exception("MapWriter.writeShapes is abstract")
103
104 - def writeBackgrounds(self, backgrounds, color):
105 """ 106 Brief Description 107 @type backgrounds: Parallax[] 108 @param backgrounds: Placeholder 109 @type color: graphics.RGBA 110 @param color: the background fill color 111 """ 112 raise Exception("MapWriter.writeBackgrounds is abstract")
113
114 - def writeImages(self, images):
115 """ 116 Writes images to the file 117 @type images: string[] 118 @param images: the images to write 119 """ 120 raise Exception("MapWriter.writeImages is abstract")
121
122 123 -class XMLMapWriter(MapWriter):
124 - def __init__(self, fileName):
125 MapWriter.__init__(self, fileName) 126 self.__document = xml.dom.minidom.Document() 127 self.__mapElement = self.__document.createElement("tilemap") 128 self.__document.appendChild(self.__mapElement)
129
130 - def finish(self):
131 documentString = self.__document.toprettyxml(indent="\t", 132 encoding="UTF-8") 133 outFile = open(self.getFileName(), "w") 134 outFile.write(documentString) 135 outFile.close()
136
137 - def writeInfo(self, width, height, tileSize, name, description):
138 self.__mapElement.setAttribute("width", str(int(width))) 139 self.__mapElement.setAttribute("height", str(int(height))) 140 self.__mapElement.setAttribute("tilesize", str(int(tileSize))) 141 nameElement = self.__document.createElement("name") 142 nameElement.appendChild(self.__document.createTextNode(name)) 143 self.__mapElement.appendChild(nameElement) 144 descriptionElement = self.__document.createElement("description") 145 descriptionElement.appendChild(self.__document.createTextNode( 146 description)) 147 self.__mapElement.appendChild(descriptionElement)
148
149 - def writeLights(self, lights):
150 lightsElement = self.__document.createElement("lights") 151 for light in lights: 152 self.__writeLight(light, lightsElement) 153 self.__mapElement.appendChild(lightsElement)
154
155 - def writeLayers(self, layers):
156 layersElement = self.__document.createElement("layers") 157 for index, layer in enumerate(layers): 158 self.__writeLayer(layer, index, layersElement) 159 self.__mapElement.appendChild(layersElement)
160
161 - def writeShapes(self, shapeList):
162 shapesElement = self.__document.createElement("shapes") 163 for shape in shapeList: 164 if isinstance(shape, shapes.Circle): 165 self.__writeCircle(shape, shapesElement) 166 elif isinstance(shape, shapes.Polygon): 167 self.__writePolygon(shape, shapesElement) 168 else: 169 log.error("Invalid shape type") 170 self.__mapElement.appendChild(shapesElement)
171
172 - def writeBackgrounds(self, backgrounds, color):
173 backgroundsElement = self.__document.createElement("background") 174 backgroundsElement.setAttribute("color", "#%08x" % color.toU32()) 175 for background in backgrounds: 176 self.__writeBackground(background, backgroundsElement) 177 self.__mapElement.appendChild(backgroundsElement)
178
179 - def writeImages(self, images):
180 imagesElement = self.__document.createElement("images") 181 for index, fileName in enumerate(images): 182 self.__writeImage(fileName, index, imagesElement) 183 self.__mapElement.appendChild(imagesElement)
184
185 - def __writeImage(self, fileName, index, e):
186 """ 187 Brief Description 188 @type fileName: string 189 @param fileName: Placeholder 190 @type index: int 191 @param index: Placeholder 192 @type e: xml.dom.minidom.Element 193 @param e: Placeholder 194 """ 195 imageElement = self.__document.createElement("img") 196 imageElement.setAttribute("index", str(index)) 197 if preferences.files["use_prefixes"]: 198 fn = os.path.join(preferences.files["tileset_prefix"], 199 os.path.basename(str(fileName))) 200 else: 201 fn = str(fileName) 202 imageElement.setAttribute("src", fn) 203 e.appendChild(imageElement)
204
205 - def __writeLayer(self, l, index, e):
206 """ 207 Brief Description 208 @type l: Layer 209 @param l: Placeholder 210 @type index: int 211 @param index: Placeholder 212 @type e: xml.dom.minidom.Element 213 @param e: Placeholder 214 """ 215 layerElement = self.__document.createElement("layer") 216 layerElement.setAttribute("z", str(int(index))) 217 layerElement.setAttribute("visible", str(bool(l.visible))) 218 layerElement.setAttribute("name", str(l.name)) 219 for coords, tile in l.tiles.iteritems(): 220 self.__writeTile(tile, coords[0], coords[1], layerElement) 221 e.appendChild(layerElement)
222
223 - def __writeTile(self, t, x, y, e):
224 """ 225 Brief Description 226 @type t: Tile 227 @param t: Placeholder 228 @type x: int 229 @param x: Placeholder 230 @type y: int 231 @param y: Placeholder 232 @type e: xml.dom.minidom.Element 233 @param e: Placeholder 234 """ 235 tileElement = self.__document.createElement("tile") 236 tileElement.setAttribute("x", str(int(x))) 237 tileElement.setAttribute("y", str(int(y))) 238 ix, iy, index = t.getImageInfo() 239 tileElement.setAttribute("ix", str(int(ix))) 240 tileElement.setAttribute("iy", str(int(iy))) 241 tileElement.setAttribute("img", str(int(index))) 242 e.appendChild(tileElement)
243
244 - def __writeCircle(self, c, e):
245 """ 246 Brief Description 247 @type c: Circle 248 @param c: Placeholder 249 @type e: xml.dom.minidom.Element 250 @param e: Placeholder 251 """ 252 circleElement = self.__document.createElement("circle") 253 self.__writePoint(c.getCenter(), circleElement) 254 circleElement.setAttribute("radius", str(int(c.getRadius()))) 255 circleElement.setAttribute("friction", str(float(c.friction))) 256 circleElement.setAttribute("restitution", str(float(c.restitution))) 257 circleElement.setAttribute("damage", str(float(c.damage))) 258 e.appendChild(circleElement)
259
260 - def __writePolygon(self, p, e):
261 """ 262 Brief Description 263 @type p: Polygon 264 @param p: Placeholder 265 @type e: xml.dom.minidom.Element 266 @param e: Placeholder 267 """ 268 polygonElement = self.__document.createElement("polygon") 269 polygonElement.setAttribute("friction", str(float(p.friction))) 270 polygonElement.setAttribute("restitution", str(float(p.restitution))) 271 polygonElement.setAttribute("damage", str(float(p.damage))) 272 for point in p.getPoints(): 273 self.__writePoint(point, polygonElement) 274 e.appendChild(polygonElement)
275
276 - def __writePoint(self, p, e):
277 """ 278 Brief Description 279 @type p: Point 280 @param p: Placeholder 281 @type e: xml.dom.minidom.Element 282 @param e: Placeholder 283 """ 284 pointElement = self.__document.createElement("point") 285 pointElement.setAttribute("x", str(int(p.x))) 286 pointElement.setAttribute("y", str(int(p.y))) 287 e.appendChild(pointElement)
288
289 - def __writeBackground(self, background, e):
290 parallaxElement = self.__document.createElement("parallax") 291 if preferences.file["use_prefixes"]: 292 fn = os.path.join(preferences.files["parallax_prefix"], 293 os.path.basename(str(background.fileName))) 294 else: 295 fn = str(background.fileName) 296 parallaxElement.setAttribute("filename", fn) 297 parallaxElement.setAttribute("vtile", str(bool(background.vTile))) 298 parallaxElement.setAttribute("htile", str(bool(background.hTile))) 299 parallaxElement.setAttribute("vscroll", str(bool(background.vScroll))) 300 parallaxElement.setAttribute("hscroll", str(bool(background.hScroll))) 301 parallaxElement.setAttribute("vscrollspeed", str(float(background.vScrollSpeed))) 302 parallaxElement.setAttribute("hscrollspeed", str(float(background.hScrollSpeed))) 303 parallaxElement.setAttribute("visible", str(bool(background.visible))) 304 e.appendChild(parallaxElement)
305
306 307 -class JSONMapWriter(MapWriter):
308 - def __init__(self):
309 pass
310
311 312 -class BinaryMapWriter(MapWriter):
313 - def __init__(self, fileName):
314 MapWriter.__init__(self, fileName) 315 self.__tileData = [] 316 self.__width = 0 317 self.__height = 0
318
319 - def writeInfo(self, width, height, tileSize, name, description):
320 self.__width = width 321 self.__height = height
322 323
324 - def writeLayers(self, layers):
325 for layer in layers: 326 self.__tileData.append(self.__writeLayer(layer))
327
328 - def __writeLayer(self, layer):
329 st = "" 330 for i in range(self.__width): 331 for j in range(self.__height): 332 if (i, j) in layer.tiles: 333 ix, iy, index = layer.tiles[(i, j)].getImageInfo() 334 st = st + struct.pack('h', (iy * width) + ix)
335
336 337 -class MapReader:
338 """ 339 Base class for map readers 340 """ 341
342 - def __init__(self, fileName):
343 """ 344 @type fileName: string 345 @param fileName: Name of file to open 346 """ 347 self.__fileName = fileName 348 self.map = tilemap.TileMap() 349 try: 350 self.file = open(fileName, "r") 351 except IOError, e: 352 print e 353 self.map = None
354 355 @staticmethod
356 - def getReader(fileName):
357 """ 358 @type fileName: string 359 @param fileName: the name of the file to read 360 @rtype: MapReader 361 @return: a map reader appropriate for the file type 362 """ 363 base, ext = os.path.splitext(fileName) 364 ext = str.upper(ext)[1:] 365 if ext == "XML": 366 return XMLMapReader(fileName) 367 elif ext == "JSON": 368 return JSONMapReader(fileName) 369 else: 370 raise Exception("No reader class for file type \"" + ext + "\"")
371
372 - def getMap(self):
373 """ 374 @rtype: TileMap 375 @return: the completed map 376 """ 377 return self.map
378
379 380 -class XMLMapReader(MapReader):
381 - def __init__(self, fileName):
382 MapReader.__init__(self, fileName) 383 if self.map == None: 384 return 385 else: 386 try: 387 self.__document = xml.dom.minidom.parse(self.file) 388 except Exception, ParseException: 389 log.error(parseException) 390 self.map = None 391 return 392 mapElement = self.__document.documentElement 393 self.__processTileMapElement(mapElement) 394 for e in mapElement.getElementsByTagName("name"): 395 self.__processNameElement(e) 396 for e in mapElement.getElementsByTagName("description"): 397 self.__processDescriptionElement(e) 398 for e in mapElement.getElementsByTagName("layers"): 399 for layerElement in e.getElementsByTagName("layer"): 400 self.__processLayer(layerElement) 401 for e in mapElement.getElementsByTagName("background"): 402 self.__processBackground(e) 403 for e in mapElement.getElementsByTagName("shapes"): 404 for p in e.getElementsByTagName("polygon"): 405 self.__processPolygon(p) 406 for c in e.getElementsByTagName("circle"): 407 self.__processCircle(c) 408 for e in mapElement.getElementsByTagName("images"): 409 for i in e.getElementsByTagName("img"): 410 self.__processImages(i) 411 for e in mapElement.getElementsByTagName("lights"): 412 for l in e.getElementsByTagName("light"): 413 self.__processLights(e)
414
415 - def __processNameElement(self, e):
416 name = e.childNodes[0] 417 if name.nodeType == name.TEXT_NODE: 418 self.map.name = name.data.strip() 419 else: 420 log.error("<name> contents is not a text node")
421
422 - def __processDescriptionElement(self, e):
423 description = e.childNodes[0] 424 if description.nodeType == description.TEXT_NODE: 425 self.map.description = description.data.strip() 426 else: 427 log.error("<description> contents is not a text node")
428
429 - def __processTileMapElement(self, e):
430 if XMLMapReader.__requireAttributes(e, "width", "height", "tilesize") \ 431 == False: 432 log.error("Required attribute of tilemap element not found") 433 else: 434 self.map.width = int(e.attributes["width"].value) 435 self.map.height = int(e.attributes["height"].value) 436 self.map.tileSize = int(e.attributes["tilesize"].value)
437
438 - def __processLights(self, e):
439 """ 440 Brief Description 441 @type e: xml.dom.minidom.Element 442 @param e: Placeholder 443 """ 444 pass
445
446 - def __processImages(self, e):
447 """ 448 Brief Description 449 @type e: xml.dom.minidom.Element 450 @param e: Placeholder 451 """ 452 XMLMapReader.__requireAttributes(e, "src", "index") 453 src = datafiles.getTilesetPath(str(e.attributes["src"].value)) 454 if os.path.exists(src) == False: 455 raise datafiles.FileNotFoundError(src) 456 index = int(e.attributes["index"].value) 457 self.map.addImage(src, index)
458
459 - def __processLayer(self, e):
460 """ 461 Reads through a layer element and adds its information to the maps 462 @type e: xml.dom.minidom.Element 463 @param e: Placeholder 464 """ 465 if XMLMapReader.__requireAttributes(e, "z", "visible", "name") == False: 466 logw("Layer has no z value") 467 else: 468 z = int(e.attributes["z"].value) 469 # >>> bool("False") 470 # True 471 # >>> print "WTF?!" 472 v = bool(e.attributes["visible"].value != "False") 473 n = str(e.attributes["name"].value) 474 self.map.addLayer(n, v, z) 475 for tileElement in e.getElementsByTagName("tile"): 476 t, x, y = self.__processTile(tileElement) 477 self.map.addTile(t, x, y, z)
478
479 - def __processTile(self, e):
480 """ 481 Brief Description 482 @type e: xml.dom.minidom.Element 483 @param e: Placeholder 484 @rtype: (Tile, int, int) 485 @return: Tile tile parsed from e and its x and y coordinates 486 """ 487 if XMLMapReader.__requireAttributes(e, "img", "x", "y", "ix", "iy") \ 488 == False: 489 log.erorr("Error in __processTile: Required attributes not present") 490 return None 491 else: 492 img = int(e.attributes["img"].value) 493 ix = int(e.attributes["ix"].value) 494 iy = int(e.attributes["iy"].value) 495 x = int(e.attributes["x"].value) 496 y = int(e.attributes["y"].value) 497 t = tilemap.Tile(img, ix, iy) 498 return t, x, y
499
500 - def __processCircle(self, e):
501 """ 502 Brief Description 503 @type e: xml.dom.minidom.Element 504 @param e: Placeholder 505 """ 506 if XMLMapReader.__requireAttributes(e, "radius", "friction", 507 "restitution", "damage") == False: 508 log.error("Required attributes of circle tag not found") 509 return False 510 else: 511 radius = int(e.attributes["radius"].value) 512 friction = float(e.attributes["friction"].value) 513 restitution = float(e.attributes["restitution"].value) 514 center = None 515 for pointElement in e.getElementsByTagName("point"): 516 center = self.__processPoint(pointElement) 517 c = shapes.Circle(radius) 518 c.setCenter(center) 519 c.friction = float(e.attributes["friction"].value) 520 c.restitution = float(e.attributes["restitution"].value) 521 c.damage = float(e.attributes["damage"].value) 522 self.map.addShape(c)
523
524 - def __processPolygon(self, e):
525 """ 526 Brief Description 527 @type e: xml.dom.minidom.Element 528 @param e: Placeholder 529 """ 530 if XMLMapReader.__requireAttributes(e, "friction", 531 "restitution", "damage") == False: 532 log.error("Required attributes of circle tag not found") 533 return False 534 else: 535 points = [] 536 for pointElement in e.getElementsByTagName("point"): 537 points.append(self.__processPoint(pointElement)) 538 p = shapes.Polygon(points) 539 p.friction = float(e.attributes["friction"].value) 540 p.restitution = float(e.attributes["restitution"].value) 541 p.damage = float(e.attributes["damage"].value) 542 self.map.addShape(p)
543
544 - def __processPoint(self, e):
545 """ 546 Brief Description 547 @type e: xml.dom.minidom.Element 548 @param e: Placeholder 549 """ 550 if XMLMapReader.__requireAttributes(e, "x", "y") == False: 551 return None 552 else: 553 x = int(e.attributes["x"].value) 554 y = int(e.attributes["y"].value) 555 return shapes.Point(x, y)
556
557 - def __processBackground(self, e):
558 if XMLMapReader.__requireAttributes(e, "color") == False: 559 log.error("Required attribute of <background> tag not found") 560 return None 561 562 self.map.bgColor = graphics.RGBA() 563 self.map.bgColor.fromU32(int(e.attributes["color"].value[1:], 16)) 564 565 for parallaxElement in e.getElementsByTagName("parallax"): 566 self.__processParallax(parallaxElement)
567
568 - def __processParallax(self, e):
569 if XMLMapReader.__requireAttributes(e, "filename", "vtile", "vscroll", 570 "hscroll", "vscrollspeed", "hscrollspeed", "visible") == False: 571 log.error("Required attributes of <parallax> tag not found") 572 return None 573 else: 574 p = tilemap.Parallax() 575 p.fileName = datafiles.getParallaxPath( 576 e.attributes["filename"].value) 577 if os.path.exists(p.fileName) == False: 578 raise datafiles.FileNotFoundError(p.fileName) 579 p.vTile = bool(e.attributes["vtile"].value != "False") 580 p.hTile = bool(e.attributes["htile"].value != "False") 581 p.vScroll = bool(e.attributes["vscroll"].value != "False") 582 p.hScroll = bool(e.attributes["hscroll"].value != "False") 583 p.vScrollSpeed = float(e.attributes["vscrollspeed"].value) 584 p.hScrollSpeed = float(e.attributes["hscrollspeed"].value) 585 p.visible = bool(e.attributes["visible"].value != "False") 586 self.map.backgrounds.append(p)
587 588 @staticmethod
589 - def __requireAttributes(element, *names):
590 """ 591 @type element: xml.dom.minidom.Element 592 @param element: the xml element to test 593 @type names: string[] 594 @param names: List of attributes that are required 595 @rtype: bool 596 @return: True if all the required attrubutes were present 597 in the element, False otherwise 598 """ 599 for name in names: 600 if name not in element.attributes.keys(): 601 log.warn("Attribute " + name + " of " + element.tagName 602 + " not found") 603 return False 604 return True
605
606 607 -class JSONMapReader(MapReader):
608 pass
609