1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * @constant
 29  * @type Number
 30  */
 31 cc.TMX_LAYER_ATTRIB_NONE = 1 << 0;
 32 /**
 33  * @constant
 34  * @type Number
 35  */
 36 cc.TMX_LAYER_ATTRIB_BASE64 = 1 << 1;
 37 /**
 38  * @constant
 39  * @type Number
 40  */
 41 cc.TMX_LAYER_ATTRIB_GZIP = 1 << 2;
 42 /**
 43  * @constant
 44  * @type Number
 45  */
 46 cc.TMX_LAYER_ATTRIB_ZLIB = 1 << 3;
 47 
 48 /**
 49  * @constant
 50  * @type Number
 51  */
 52 cc.TMX_PROPERTY_NONE = 0;
 53 
 54 /**
 55  * @constant
 56  * @type Number
 57  */
 58 cc.TMX_PROPERTY_MAP = 1;
 59 
 60 /**
 61  * @constant
 62  * @type Number
 63  */
 64 cc.TMX_PROPERTY_LAYER = 2;
 65 
 66 /**
 67  * @constant
 68  * @type Number
 69  */
 70 cc.TMX_PROPERTY_OBJECTGROUP = 3;
 71 
 72 /**
 73  * @constant
 74  * @type Number
 75  */
 76 cc.TMX_PROPERTY_OBJECT = 4;
 77 
 78 /**
 79  * @constant
 80  * @type Number
 81  */
 82 cc.TMX_PROPERTY_TILE = 5;
 83 
 84 /**
 85  * @constant
 86  * @type Number
 87  */
 88 cc.TMX_TILE_HORIZONTAL_FLAG = 0x80000000;
 89 
 90 
 91 /**
 92  * @constant
 93  * @type Number
 94  */
 95 cc.TMX_TILE_VERTICAL_FLAG = 0x40000000;
 96 
 97 /**
 98  * @constant
 99  * @type Number
100  */
101 cc.TMX_TILE_DIAGONAL_FLAG = 0x20000000;
102 
103 /**
104  * @constant
105  * @type Number
106  */
107 cc.TMX_TILE_FLIPPED_ALL = (cc.TMX_TILE_HORIZONTAL_FLAG | cc.TMX_TILE_VERTICAL_FLAG | cc.TMX_TILE_DIAGONAL_FLAG) >>> 0;
108 
109 /**
110  * @constant
111  * @type Number
112  */
113 cc.TMX_TILE_FLIPPED_MASK = (~(cc.TMX_TILE_FLIPPED_ALL)) >>> 0;
114 
115 // Bits on the far end of the 32-bit global tile ID (GID's) are used for tile flags
116 
117 /**
118  * <p>cc.TMXLayerInfo contains the information about the layers like: <br />
119  * - Layer name<br />
120  * - Layer size <br />
121  * - Layer opacity at creation time (it can be modified at runtime)  <br />
122  * - Whether the layer is visible (if it's not visible, then the CocosNode won't be created) <br />
123  *  <br />
124  * This information is obtained from the TMX file.</p>
125  * @class
126  * @extends cc.Class
127  *
128  * @property {Array}    properties  - Properties of the layer info.
129  */
130 cc.TMXLayerInfo = cc.Class.extend(/** @lends cc.TMXLayerInfo# */{
131     properties:null,
132 
133 	name:"",
134     _layerSize:null,
135     _tiles:null,
136     visible:null,
137     _opacity:null,
138     ownTiles:true,
139     _minGID:100000,
140     _maxGID:0,
141     offset:null,
142 
143     ctor:function () {
144         this.properties = [];
145         this.name = "";
146         this._layerSize = null;
147         this._tiles = [];
148         this.visible = true;
149         this._opacity = 0;
150         this.ownTiles = true;
151         this._minGID = 100000;
152         this._maxGID = 0;
153         this.offset = cc.p(0,0);
154     },
155 
156     /**
157      * @return {Array}
158      */
159     getProperties:function () {
160         return this.properties;
161     },
162 
163     /**
164      * @param {object} value
165      */
166     setProperties:function (value) {
167         this.properties = value;
168     }
169 });
170 
171 /**
172  * <p>cc.TMXTilesetInfo contains the information about the tilesets like: <br />
173  * - Tileset name<br />
174  * - Tileset spacing<br />
175  * - Tileset margin<br />
176  * - size of the tiles<br />
177  * - Image used for the tiles<br />
178  * - Image size<br />
179  *
180  * This information is obtained from the TMX file. </p>
181  * @class
182  * @extends cc.Class
183  */
184 cc.TMXTilesetInfo = cc.Class.extend(/** @lends cc.TMXTilesetInfo# */{
185 
186     /**
187      * Tileset name
188      */
189     name:"",
190 
191     /**
192      * First grid
193      */
194     firstGid:0,
195     _tileSize:null,
196 
197     /**
198      * Spacing
199      */
200     spacing:0,
201 
202     /**
203      *  Margin
204      */
205     margin:0,
206 
207     /**
208      * Filename containing the tiles (should be sprite sheet / texture atlas)
209      */
210     sourceImage:"",
211 
212     /**
213      * Size in pixels of the image
214      */
215     imageSize:null,
216 
217     ctor:function () {
218         this._tileSize = cc.size(0, 0);
219         this.imageSize = cc.size(0, 0);
220     },
221 
222     /**
223      * @param {Number} gid
224      * @return {cc.Rect}
225      */
226     rectForGID:function (gid) {
227         var rect = cc.rect(0, 0, 0, 0);
228         rect.width = this._tileSize.width;
229         rect.height = this._tileSize.height;
230         gid &= cc.TMX_TILE_FLIPPED_MASK;
231         gid = gid - parseInt(this.firstGid, 10);
232         var max_x = parseInt((this.imageSize.width - this.margin * 2 + this.spacing) / (this._tileSize.width + this.spacing), 10);
233         rect.x = parseInt((gid % max_x) * (this._tileSize.width + this.spacing) + this.margin, 10);
234         rect.y = parseInt(parseInt(gid / max_x, 10) * (this._tileSize.height + this.spacing) + this.margin, 10);
235         return rect;
236     }
237 });
238 
239 /**
240  * <p>cc.TMXMapInfo contains the information about the map like: <br/>
241  *- Map orientation (hexagonal, isometric or orthogonal)<br/>
242  *- Tile size<br/>
243  *- Map size</p>
244  *
245  * <p>And it also contains: <br/>
246  * - Layers (an array of TMXLayerInfo objects)<br/>
247  * - Tilesets (an array of TMXTilesetInfo objects) <br/>
248  * - ObjectGroups (an array of TMXObjectGroupInfo objects) </p>
249  *
250  * <p>This information is obtained from the TMX file. </p>
251  * @class
252  * @extends cc.saxParser
253  *
254  * @property {Array}    properties          - Properties of the map info.
255  * @property {Number}   orientation         - Map orientation.
256  * @property {Object}   parentElement       - Parent element.
257  * @property {Number}   parentGID           - Parent GID.
258  * @property {Object}   layerAttrs        - Layer attributes.
259  * @property {Boolean}  storingCharacters   - Is reading storing characters stream.
260  * @property {String}   tmxFileName         - TMX file name.
261  * @property {String}   currentString       - Current string stored from characters stream.
262  * @property {Number}   mapWidth            - Width of the map
263  * @property {Number}   mapHeight           - Height of the map
264  * @property {Number}   tileWidth           - Width of a tile
265  * @property {Number}   tileHeight          - Height of a tile
266  */
267 cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{
268 	properties:null,
269     orientation:null,
270 	parentElement:null,
271 	parentGID:null,
272 	layerAttrs:0,
273 	storingCharacters:false,
274 	tmxFileName:null,
275 	currentString:null,
276 
277 	_objectGroups:null,
278     _mapSize:null,
279     _tileSize:null,
280     _layers:null,
281     _tilesets:null,
282     // tile properties
283     _tileProperties:null,
284     _resources:"",
285     _currentFirstGID:0,
286 
287     ctor:function () {
288         cc.SAXParser.prototype.ctor.apply(this);
289         this._mapSize = cc.size(0, 0);
290         this._tileSize = cc.size(0, 0);
291         this._layers = [];
292         this._tilesets = [];
293         this._objectGroups = [];
294         this.properties = [];
295         this._tileProperties = {};
296 
297         this._currentFirstGID = 0;
298     },
299     /**
300      * @return {Number}
301      */
302     getOrientation:function () {
303         return this.orientation;
304     },
305 
306     /**
307      * @param {Number} value
308      */
309     setOrientation:function (value) {
310         this.orientation = value;
311     },
312 
313     /**
314      * Map width & height
315      * @return {cc.Size}
316      */
317     getMapSize:function () {
318         return cc.size(this._mapSize.width,this._mapSize.height);
319     },
320 
321     /**
322      * @param {cc.Size} value
323      */
324     setMapSize:function (value) {
325         this._mapSize.width = value.width;
326         this._mapSize.height = value.height;
327     },
328 
329 	_getMapWidth: function () {
330 		return this._mapSize.width;
331 	},
332 	_setMapWidth: function (width) {
333 		this._mapSize.width = width;
334 	},
335 	_getMapHeight: function () {
336 		return this._mapSize.height;
337 	},
338 	_setMapHeight: function (height) {
339 		this._mapSize.height = height;
340 	},
341 
342     /**
343      * Tiles width & height
344      * @return {cc.Size}
345      */
346     getTileSize:function () {
347         return cc.size(this._tileSize.width, this._tileSize.height);
348     },
349 
350     /**
351      * @param {cc.Size} value
352      */
353     setTileSize:function (value) {
354         this._tileSize.width = value.width;
355         this._tileSize.height = value.height;
356     },
357 
358 	_getTileWidth: function () {
359 		return this._tileSize.width;
360 	},
361 	_setTileWidth: function (width) {
362 		this._tileSize.width = width;
363 	},
364 	_getTileHeight: function () {
365 		return this._tileSize.height;
366 	},
367 	_setTileHeight: function (height) {
368 		this._tileSize.height = height;
369 	},
370 
371     /**
372      * Layers
373      * @return {Array}
374      */
375     getLayers:function () {
376         return this._layers;
377     },
378 
379     /**
380      * @param {cc.TMXLayerInfo} value
381      */
382     setLayers:function (value) {
383         this._layers.push(value);
384     },
385 
386     /**
387      * tilesets
388      * @return {Array}
389      */
390     getTilesets:function () {
391         return this._tilesets;
392     },
393 
394     /**
395      * @param {cc.TMXTilesetInfo} value
396      */
397     setTilesets:function (value) {
398         this._tilesets.push(value);
399     },
400 
401     /**
402      * ObjectGroups
403      * @return {Array}
404      */
405     getObjectGroups:function () {
406         return this._objectGroups;
407     },
408 
409     /**
410      * @param {cc.TMXObjectGroup} value
411      */
412     setObjectGroups:function (value) {
413         this._objectGroups.push(value);
414     },
415 
416     /**
417      * parent element
418      * @return {Object}
419      */
420     getParentElement:function () {
421         return this.parentElement;
422     },
423 
424     /**
425      * @param {Object} value
426      */
427     setParentElement:function (value) {
428         this.parentElement = value;
429     },
430 
431     /**
432      * parent GID
433      * @return {Number}
434      */
435     getParentGID:function () {
436         return this.parentGID;
437     },
438 
439     /**
440      * @param {Number} value
441      */
442     setParentGID:function (value) {
443         this.parentGID = value;
444     },
445 
446     /**
447      * Layer attribute
448      * @return {Object}
449      */
450     getLayerAttribs:function () {
451         return this.layerAttrs;
452     },
453 
454     /**
455      * @param {Object} value
456      */
457     setLayerAttribs:function (value) {
458         this.layerAttrs = value;
459     },
460 
461     /**
462      * Is reading storing characters stream
463      * @return {Boolean}
464      */
465     getStoringCharacters:function () {
466         return this.storingCharacters;
467     },
468 
469     /**
470      * @param {Boolean} value
471      */
472     setStoringCharacters:function (value) {
473         this.storingCharacters = value;
474     },
475 
476     /**
477      * Properties
478      * @return {Array}
479      */
480     getProperties:function () {
481         return this.properties;
482     },
483 
484     /**
485      * @param {object} value
486      */
487     setProperties:function (value) {
488         this.properties = value;
489     },
490 
491     /**
492      * Initializes a TMX format with a  tmx file
493      * @param {String} tmxFile
494      * @return {Element}
495      */
496     initWithTMXFile:function (tmxFile) {
497         this._internalInit(tmxFile, null);
498         return this.parseXMLFile(tmxFile);
499     },
500 
501     /**
502      * initializes a TMX format with an XML string and a TMX resource path
503      * @param {String} tmxString
504      * @param {String} resourcePath
505      * @return {Boolean}
506      */
507     initWithXML:function (tmxString, resourcePath) {
508         this._internalInit(null, resourcePath);
509         return this.parseXMLString(tmxString);
510     },
511 
512     /** Initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file
513      * @param {String} tmxFile
514      * @param {boolean} [isXmlString=false]
515      * @return {Element}
516      */
517     parseXMLFile:function (tmxFile, isXmlString) {
518         isXmlString = isXmlString || false;
519 	    var xmlStr = isXmlString ? tmxFile : cc.loader.getRes(tmxFile);
520         if(!xmlStr) throw "Please load the resource first : " + tmxFile;
521 
522         var mapXML = this._parseXML(xmlStr);
523         var i, j;
524 
525         // PARSE <map>
526         var map = mapXML.documentElement;
527 
528         var version = map.getAttribute('version');
529         var orientationStr = map.getAttribute('orientation');
530 
531         if (map.nodeName == "map") {
532             if (version != "1.0" && version !== null)
533                 cc.log("cocos2d: TMXFormat: Unsupported TMX version:" + version);
534 
535             if (orientationStr == "orthogonal")
536                 this.orientation = cc.TMX_ORIENTATION_ORTHO;
537             else if (orientationStr == "isometric")
538                 this.orientation = cc.TMX_ORIENTATION_ISO;
539             else if (orientationStr == "hexagonal")
540                 this.orientation = cc.TMX_ORIENTATION_HEX;
541             else if (orientationStr !== null)
542                 cc.log("cocos2d: TMXFomat: Unsupported orientation:" + orientationStr);
543 
544             var mapSize = cc.size(0, 0);
545             mapSize.width = parseFloat(map.getAttribute('width'));
546             mapSize.height = parseFloat(map.getAttribute('height'));
547             this.setMapSize(mapSize);
548 
549             mapSize = cc.size(0, 0);
550             mapSize.width = parseFloat(map.getAttribute('tilewidth'));
551             mapSize.height = parseFloat(map.getAttribute('tileheight'));
552             this.setTileSize(mapSize);
553 
554             // The parent element is the map
555             var propertyArr = map.querySelectorAll("map > properties >  property");
556             if (propertyArr) {
557                 var aPropertyDict = {};
558                 for (i = 0; i < propertyArr.length; i++) {
559                     aPropertyDict[propertyArr[i].getAttribute('name')] = propertyArr[i].getAttribute('value');
560                 }
561                 this.properties = aPropertyDict;
562             }
563         }
564 
565         // PARSE <tileset>
566         var tilesets = map.getElementsByTagName('tileset');
567         if (map.nodeName !== "map") {
568             tilesets = [];
569             tilesets.push(map);
570         }
571 
572         for (i = 0; i < tilesets.length; i++) {
573             var selTileset = tilesets[i];
574             // If this is an external tileset then start parsing that
575             var tsxName = selTileset.getAttribute('source');
576             if (tsxName) {
577                 //this._currentFirstGID = parseInt(selTileset.getAttribute('firstgid'));
578                 var tsxPath = isXmlString ? cc.path.join(this._resources, tsxName) : cc.path.changeBasename(tmxFile, tsxName);
579                 this.parseXMLFile(tsxPath);
580             } else {
581                 var tileset = new cc.TMXTilesetInfo();
582                 tileset.name = selTileset.getAttribute('name') || "";
583                 //TODO need fix
584                 //if(this._currentFirstGID === 0){
585                 tileset.firstGid = parseInt(selTileset.getAttribute('firstgid')) || 0;
586                 //}else{
587                 //    tileset.firstGid = this._currentFirstGID;
588                 //    this._currentFirstGID = 0;
589                 //}
590 
591                 tileset.spacing = parseInt(selTileset.getAttribute('spacing')) || 0;
592                 tileset.margin = parseInt(selTileset.getAttribute('margin')) || 0;
593 
594                 var tilesetSize = cc.size(0, 0);
595                 tilesetSize.width = parseFloat(selTileset.getAttribute('tilewidth'));
596                 tilesetSize.height = parseFloat(selTileset.getAttribute('tileheight'));
597                 tileset._tileSize = tilesetSize;
598 
599                 var image = selTileset.getElementsByTagName('image')[0];
600                 var imagename = image.getAttribute('source');
601                 var num = -1;
602                 if(this.tmxFileName)
603                     num  = this.tmxFileName.lastIndexOf("/");
604                 if (num !== -1) {
605                     var dir = this.tmxFileName.substr(0, num + 1);
606                     tileset.sourceImage = dir + imagename;
607                 } else {
608                     tileset.sourceImage = this._resources + (this._resources ? "/" : "") + imagename;
609                 }
610                 this.setTilesets(tileset);
611             }
612         }
613 
614         // PARSE  <tile>
615         var tiles = map.querySelectorAll('tile');
616         if (tiles) {
617             for (i = 0; i < tiles.length; i++) {
618                 var info = this._tilesets[0];
619                 var t = tiles[i];
620                 this.parentGID = parseInt(info.firstGid) + parseInt(t.getAttribute('id') || 0);
621                 var tp = t.querySelectorAll("properties > property");
622                 if (tp) {
623                     var dict = {};
624                     for (j = 0; j < tp.length; j++) {
625                         var name = tp[j].getAttribute('name');
626                         dict[name] = tp[j].getAttribute('value');
627                     }
628                     this._tileProperties[this.parentGID] = dict;
629                 }
630             }
631         }
632 
633         // PARSE  <layer>
634         var layers = map.getElementsByTagName('layer');
635         if (layers) {
636             for (i = 0; i < layers.length; i++) {
637                 var selLayer = layers[i];
638                 var data = selLayer.getElementsByTagName('data')[0];
639 
640                 var layer = new cc.TMXLayerInfo();
641                 layer.name = selLayer.getAttribute('name');
642 
643                 var layerSize = cc.size(0, 0);
644                 layerSize.width = parseFloat(selLayer.getAttribute('width'));
645                 layerSize.height = parseFloat(selLayer.getAttribute('height'));
646                 layer._layerSize = layerSize;
647 
648                 var visible = selLayer.getAttribute('visible');
649                 layer.visible = !(visible == "0");
650 
651                 var opacity = selLayer.getAttribute('opacity') || 1;
652 
653                 if (opacity)
654                     layer._opacity = parseInt(255 * parseFloat(opacity));
655                 else
656                     layer._opacity = 255;
657                 layer.offset = cc.p(parseFloat(selLayer.getAttribute('x')) || 0, parseFloat(selLayer.getAttribute('y')) || 0);
658 
659                 var nodeValue = '';
660                 for (j = 0; j < data.childNodes.length; j++) {
661                     nodeValue += data.childNodes[j].nodeValue
662                 }
663                 nodeValue = nodeValue.trim();
664 
665                 // Unpack the tilemap data
666                 var compression = data.getAttribute('compression');
667                 var encoding = data.getAttribute('encoding');
668                 if(compression && compression !== "gzip" && compression !== "zlib"){
669                     cc.log("cc.TMXMapInfo.parseXMLFile(): unsupported compression method");
670                     return null;
671                 }
672                 switch (compression) {
673                     case 'gzip':
674                         layer._tiles = cc.unzipBase64AsArray(nodeValue, 4);
675                         break;
676                     case 'zlib':
677                         var inflator = new Zlib.Inflate(cc.Codec.Base64.decodeAsArray(nodeValue, 1));
678                         layer._tiles = cc.uint8ArrayToUint32Array(inflator.decompress());
679                         break;
680                     case null:
681                     case '':
682                         // Uncompressed
683                         if (encoding == "base64")
684                             layer._tiles = cc.Codec.Base64.decodeAsArray(nodeValue, 4);
685                         else if (encoding === "csv") {
686                             layer._tiles = [];
687                             var csvTiles = nodeValue.split(',');
688                             for (var csvIdx = 0; csvIdx < csvTiles.length; csvIdx++)
689                                 layer._tiles.push(parseInt(csvTiles[csvIdx]));
690                         } else {
691                             //XML format
692                             var selDataTiles = data.getElementsByTagName("tile");
693                             layer._tiles = [];
694                             for (var xmlIdx = 0; xmlIdx < selDataTiles.length; xmlIdx++)
695                                 layer._tiles.push(parseInt(selDataTiles[xmlIdx].getAttribute("gid")));
696                         }
697                         break;
698                     default:
699                         if(this.layerAttrs == cc.TMX_LAYER_ATTRIB_NONE)
700                             cc.log("cc.TMXMapInfo.parseXMLFile(): Only base64 and/or gzip/zlib maps are supported");
701                         break;
702                 }
703 
704                 // The parent element is the last layer
705                 var layerProps = selLayer.querySelectorAll("properties > property");
706                 if (layerProps) {
707                     var layerProp = {};
708                     for (j = 0; j < layerProps.length; j++) {
709                         layerProp[layerProps[j].getAttribute('name')] = layerProps[j].getAttribute('value');
710                     }
711                     layer.properties = layerProp;
712                 }
713                 this.setLayers(layer);
714             }
715         }
716 
717         // PARSE <objectgroup>
718         var objectGroups = map.getElementsByTagName('objectgroup');
719         if (objectGroups) {
720             for (i = 0; i < objectGroups.length; i++) {
721                 var selGroup = objectGroups[i];
722                 var objectGroup = new cc.TMXObjectGroup();
723                 objectGroup.groupName = selGroup.getAttribute('name');
724                 objectGroup.setPositionOffset(cc.p(parseFloat(selGroup.getAttribute('x')) * this.getTileSize().width || 0,
725                     parseFloat(selGroup.getAttribute('y')) * this.getTileSize().height || 0));
726 
727                 var groupProps = selGroup.querySelectorAll("objectgroup > properties > property");
728                 if (groupProps) {
729                     for (j = 0; j < groupProps.length; j++) {
730                         var groupProp = {};
731                         groupProp[groupProps[j].getAttribute('name')] = groupProps[j].getAttribute('value');
732                         // Add the property to the layer
733                         objectGroup.properties = groupProp;
734                     }
735                 }
736 
737                 var objects = selGroup.querySelectorAll('object');
738                 if (objects) {
739                     for (j = 0; j < objects.length; j++) {
740                         var selObj = objects[j];
741                         // The value for "type" was blank or not a valid class name
742                         // Create an instance of TMXObjectInfo to store the object and its properties
743                         var objectProp = {};
744 
745                         // Set the name of the object to the value for "name"
746                         objectProp["name"] = selObj.getAttribute('name') || "";
747 
748                         // Assign all the attributes as key/name pairs in the properties dictionary
749                         objectProp["type"] = selObj.getAttribute('type') || "";
750 
751                         objectProp["x"] = parseInt(selObj.getAttribute('x') || 0) + objectGroup.getPositionOffset().x;
752                         var y = parseInt(selObj.getAttribute('y') || 0) + objectGroup.getPositionOffset().y;
753 
754                         objectProp["width"] = parseInt(selObj.getAttribute('width')) || 0;
755                         objectProp["height"] = parseInt(selObj.getAttribute('height')) || 0;
756 
757                         // Correct y position. (Tiled uses Flipped, cocos2d uses Standard)
758                         objectProp["y"] = parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"];
759 
760                         var docObjProps = selObj.querySelectorAll("properties > property");
761                         if (docObjProps) {
762                             for (var k = 0; k < docObjProps.length; k++)
763                                 objectProp[docObjProps[k].getAttribute('name')] = docObjProps[k].getAttribute('value');
764                         }
765 
766                         //polygon
767                         var polygonProps = selObj.querySelectorAll("polygon");
768                         if(polygonProps && polygonProps.length > 0) {
769                             var selPgPointStr = polygonProps[0].getAttribute('points');
770                             if(selPgPointStr)
771                                 objectProp["polygonPoints"] = this._parsePointsString(selPgPointStr);
772                         }
773 
774                         //polyline
775                         var polylineProps = selObj.querySelectorAll("polyline");
776                         if(polylineProps && polylineProps.length > 0) {
777                             var selPlPointStr = polylineProps[0].getAttribute('points');
778                             if(selPlPointStr)
779                                 objectProp["polylinePoints"] = this._parsePointsString(selPlPointStr);
780                         }
781 
782                         // Add the object to the objectGroup
783                         objectGroup.setObjects(objectProp);
784                     }
785                 }
786 
787                 this.setObjectGroups(objectGroup);
788             }
789         }
790         return map;
791     },
792 
793     _parsePointsString:function(pointsString){
794          if(!pointsString)
795             return null;
796 
797         var points = [];
798         var pointsStr = pointsString.split(' ');
799         for(var i = 0; i < pointsStr.length; i++){
800             var selPointStr = pointsStr[i].split(',');
801             points.push({'x':selPointStr[0], 'y':selPointStr[1]});
802         }
803         return points;
804     },
805 
806     /**
807      * initializes parsing of an XML string, either a tmx (Map) string or tsx (Tileset) string
808      * @param {String} xmlString
809      * @return {Boolean}
810      */
811     parseXMLString:function (xmlString) {
812         return this.parseXMLFile(xmlString, true);
813     },
814 
815     /**
816      * @return {object}
817      */
818     getTileProperties:function () {
819         return this._tileProperties;
820     },
821 
822     /**
823      * @param {object} tileProperties
824      */
825     setTileProperties:function (tileProperties) {
826         this._tileProperties.push(tileProperties);
827     },
828 
829     /**
830      * @return {String}
831      */
832     getCurrentString:function () {
833         return this.currentString;
834     },
835 
836     /**
837      * @param {String} currentString
838      */
839     setCurrentString:function (currentString) {
840         this.currentString = currentString;
841     },
842 
843     /**
844      * @return {String}
845      */
846     getTMXFileName:function () {
847         return this.tmxFileName;
848     },
849 
850     /**
851      * @param {String} fileName
852      */
853     setTMXFileName:function (fileName) {
854         this.tmxFileName = fileName;
855     },
856 
857     _internalInit:function (tmxFileName, resourcePath) {
858         this._tilesets.length = 0;
859         this._layers.length = 0;
860 
861         this.tmxFileName = tmxFileName;
862         if (resourcePath)
863             this._resources = resourcePath;
864 
865         this._objectGroups.length = 0;
866         this.properties.length = 0;
867         this._tileProperties.length = 0;
868 
869         // tmp vars
870         this.currentString = "";
871         this.storingCharacters = false;
872         this.layerAttrs = cc.TMX_LAYER_ATTRIB_NONE;
873         this.parentElement = cc.TMX_PROPERTY_NONE;
874         this._currentFirstGID = 0;
875     }
876 });
877 
878 window._p = cc.TMXMapInfo.prototype;
879 
880 // Extended properties
881 /** @expose */
882 _p.mapWidth;
883 cc.defineGetterSetter(_p, "mapWidth", _p._getMapWidth, _p._setMapWidth);
884 /** @expose */
885 _p.mapHeight;
886 cc.defineGetterSetter(_p, "mapHeight", _p._getMapHeight, _p._setMapHeight);
887 /** @expose */
888 _p.tileWidth;
889 cc.defineGetterSetter(_p, "tileWidth", _p._getTileWidth, _p._setTileWidth);
890 /** @expose */
891 _p.tileHeight;
892 cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight);
893 
894 delete window._p;
895 
896 /**
897  * Creates a TMX Format with a tmx file or content string
898  * @param {String} tmxFile fileName or content string
899  * @param {String} resourcePath  If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required.
900  * @return {cc.TMXMapInfo}
901  * @example
902  * 1.
903  * //create a TMXMapInfo with file name
904  * var tmxMapInfo = cc.TMXMapInfo.create("res/orthogonal-test1.tmx");
905  * 2.
906  * //create a TMXMapInfo with content string and resource path
907  * var resources = "res/TileMaps";
908  * var filePath = "res/TileMaps/orthogonal-test1.tmx";
909  * var xmlStr = cc.loader.getRes(filePath);
910  * var tmxMapInfo = cc.TMXMapInfo.create(xmlStr, resources);
911  */
912 cc.TMXMapInfo.create = function (tmxFile, resourcePath) {
913     var ret = new cc.TMXMapInfo();
914     if (resourcePath) {
915         if (ret.initWithXML(tmxFile, resourcePath))
916             return ret;
917     } else {
918         if (ret.initWithTMXFile(tmxFile))
919             return ret;
920     }
921     return null;
922 };
923 
924 
925 cc.loader.register(["tmx", "tsx"], cc._txtLoader);
926