1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 
 25 /**
 26  * @ignore
 27  */
 28 ccs.CONST_VERSION = "version";
 29 ccs.CONST_VERSION_2_0 = 2.0;
 30 ccs.CONST_VERSION_COMBINED = 0.3;
 31 
 32 ccs.CONST_SKELETON = "skeleton";
 33 ccs.CONST_ARMATURES = "armatures";
 34 ccs.CONST_ARMATURE = "armature";
 35 ccs.CONST_BONE = "b";
 36 ccs.CONST_DISPLAY = "d";
 37 
 38 ccs.CONST_ANIMATIONS = "animations";
 39 ccs.CONST_ANIMATION = "animation";
 40 ccs.CONST_MOVEMENT = "mov";
 41 ccs.CONST_FRAME = "f";
 42 
 43 ccs.CONST_TEXTURE_ATLAS = "TextureAtlas";
 44 ccs.CONST_SUB_TEXTURE = "SubTexture";
 45 
 46 ccs.CONST_A_NAME = "name";
 47 ccs.CONST_A_DURATION = "dr";
 48 ccs.CONST_A_FRAME_INDEX = "fi";
 49 ccs.CONST_A_DURATION_TO = "to";
 50 ccs.CONST_A_DURATION_TWEEN = "drTW";
 51 ccs.CONST_A_LOOP = "lp";
 52 ccs.CONST_A_MOVEMENT_SCALE = "sc";
 53 ccs.CONST_A_MOVEMENT_DELAY = "dl";
 54 ccs.CONST_A_DISPLAY_INDEX = "dI";
 55 
 56 ccs.CONST_A_VERT = "vert";
 57 ccs.CONST_A_FRAG = "frag";
 58 ccs.CONST_A_PLIST = "plist";
 59 
 60 ccs.CONST_A_PARENT = "parent";
 61 ccs.CONST_A_SKEW_X = "kX";
 62 ccs.CONST_A_SKEW_Y = "kY";
 63 ccs.CONST_A_SCALE_X = "cX";
 64 ccs.CONST_A_SCALE_Y = "cY";
 65 ccs.CONST_A_Z = "z";
 66 ccs.CONST_A_EVENT = "evt";
 67 ccs.CONST_A_SOUND = "sd";
 68 ccs.CONST_A_SOUND_EFFECT = "sdE";
 69 ccs.CONST_A_TWEEN_EASING = "twE";
 70 ccs.CONST_A_TWEEN_ROTATION = "twR";
 71 ccs.CONST_A_EASING_PARAM = "twEP";
 72 ccs.CONST_A_IS_ARMATURE = "isArmature";
 73 ccs.CONST_A_DISPLAY_TYPE = "displayType";
 74 ccs.CONST_A_MOVEMENT = "mov";
 75 ccs.CONST_A_BLEND_TYPE = "bd";
 76 ccs.CONST_A_BLEND_SRC = "bd_src";
 77 ccs.CONST_A_BLEND_DST = "bd_dst";
 78 
 79 ccs.CONST_A_X = "x";
 80 ccs.CONST_A_Y = "y";
 81 
 82 ccs.CONST_A_COCOS2DX_X = "cocos2d_x";
 83 ccs.CONST_A_COCOS2DX_Y = "cocos2d_y";
 84 
 85 ccs.CONST_A_WIDTH = "width";
 86 ccs.CONST_A_HEIGHT = "height";
 87 ccs.CONST_A_PIVOT_X = "pX";
 88 ccs.CONST_A_PIVOT_Y = "pY";
 89 
 90 ccs.CONST_A_COCOS2D_PIVOT_X = "cocos2d_pX";
 91 ccs.CONST_A_COCOS2D_PIVOT_Y = "cocos2d_pY";
 92 
 93 ccs.CONST_A_ALPHA = "a";
 94 ccs.CONST_A_RED = "r";
 95 ccs.CONST_A_GREEN = "g";
 96 ccs.CONST_A_BLUE = "b";
 97 ccs.CONST_A_ALPHA_OFFSET = "aM";
 98 ccs.CONST_A_RED_OFFSET = "rM";
 99 ccs.CONST_A_GREEN_OFFSET = "gM";
100 ccs.CONST_A_BLUE_OFFSET = "bM";
101 ccs.CONST_A_COLOR_TRANSFORM = "colorTransform";
102 ccs.CONST_A_TWEEN_FRAME = "tweenFrame";
103 ccs.CONST_A_ROTATION = "rotation";
104 ccs.CONST_A_USE_COLOR_INFO = "uci";
105 
106 ccs.CONST_CONTOUR = "con";
107 ccs.CONST_CONTOUR_VERTEX = "con_vt";
108 
109 ccs.CONST_MOVEMENT_EVENT_FRAME = "movementEventFrame";
110 ccs.CONST_SOUND_FRAME = "soundFrame";
111 
112 ccs.CONST_FL_NAN = "NaN";
113 
114 ccs.CONST_FRAME_DATA = "frame_data";
115 ccs.CONST_MOVEMENT_BONE_DATA = "mov_bone_data";
116 ccs.CONST_MOVEMENT_FRAME_DATA = "mov_frame_data";
117 ccs.CONST_MOVEMENT_DATA = "mov_data";
118 ccs.CONST_ANIMATION_DATA = "animation_data";
119 ccs.CONST_DISPLAY_DATA = "display_data";
120 ccs.CONST_SKIN_DATA = "skin_data";
121 ccs.CONST_BONE_DATA = "bone_data";
122 ccs.CONST_ARMATURE_DATA = "armature_data";
123 ccs.CONST_CONTOUR_DATA = "contour_data";
124 ccs.CONST_TEXTURE_DATA = "texture_data";
125 ccs.CONST_VERTEX_POINT = "vertex";
126 ccs.CONST_COLOR_INFO = "color";
127 
128 ccs.CONST_CONFIG_FILE_PATH = "config_file_path";
129 ccs.CONST_CONTENT_SCALE = "content_scale";
130 
131 /**
132  * @ignore
133  * @constructor
134  */
135 ccs.DataInfo = function () {
136     this.asyncStruct = null;
137     this.configFileQueue = [];
138     this.contentScale = 1;
139     this.filename = "";
140     this.baseFilePath = "";
141     this.flashToolVersion = 0;
142     this.cocoStudioVersion = 0
143 };
144 
145 /**
146  * @namespace CocoStudio data reader helper
147  */
148 ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{
149     _configFileList: [],
150     _flashToolVersion: ccs.CONST_VERSION_2_0,
151     _cocoStudioVersion: ccs.CONST_VERSION_COMBINED,
152     _positionReadScale: 1,
153     _asyncRefCount: 0,
154     _asyncRefTotalCount: 0,
155 
156     setPositionReadScale: function (scale) {
157         this._positionReadScale = scale;
158     },
159 
160     getPositionReadScale: function () {
161         return this._positionReadScale;
162     },
163 
164     clear: function () {
165         this._configFileList = [];
166         this._asyncRefCount = 0;
167         this._asyncRefTotalCount = 0;
168     },
169 
170     addDataFromFile: function (filePath, isLoadSpriteFrame) {
171         if (this._configFileList.indexOf(filePath) != -1) {
172             return;
173         }
174         this._configFileList.push(filePath);
175 
176         this._initBaseFilePath(filePath);
177 
178         var str = cc.path.extname(filePath).toLowerCase();
179 
180         var dataInfo = new ccs.DataInfo();
181         dataInfo.filename = filePath;
182         dataInfo.basefilePath = this._initBaseFilePath(filePath);
183         if (str == ".xml") {
184             this.addDataFromXML(filePath, dataInfo);
185         }
186         else if (str == ".json" || str == ".exportjson") {
187             this.addDataFromJson(filePath, dataInfo, isLoadSpriteFrame);
188         }
189     },
190 
191     addDataFromFileAsync: function (filePath, target, selector, isLoadSpriteFrame) {
192         if (this._configFileList.indexOf(filePath) != -1) {
193             if (target && selector) {
194                 if (this._asyncRefTotalCount == 0 && this._asyncRefCount == 0)
195                     this._asyncCallBack(target, selector, 1);
196                 else
197                     this._asyncCallBack(target, selector, (this._asyncRefTotalCount - this._asyncRefCount) / this._asyncRefTotalCount);
198             }
199             return;
200         }
201         this._asyncRefTotalCount++;
202         this._asyncRefCount++;
203         var self = this;
204         var fun = function () {
205             self.addDataFromFile(filePath, isLoadSpriteFrame);
206             self._asyncRefCount--;
207             self._asyncCallBack(target, selector, (self._asyncRefTotalCount - self._asyncRefCount) / self._asyncRefTotalCount);
208         };
209         cc.director.getScheduler().scheduleCallbackForTarget(this, fun, 0.1, false);
210     },
211 
212     _asyncCallBack: function (target, selector, percent) {
213         if (target && (typeof(selector) == "string")) {
214             target[selector](percent);
215         } else if (target && (typeof(selector) == "function")) {
216             selector.call(target, percent);
217         }
218     },
219     /**
220      * find the base file path
221      * @param filePath
222      * @returns {String}
223      * @private
224      */
225     _initBaseFilePath: function (filePath) {
226         var path = filePath;
227         var pos = path.lastIndexOf("/");
228         if (pos > -1)
229             path = path.substr(0, pos + 1);
230         else
231             path = "";
232         return path;
233     },
234 
235     addDataFromXML: function (xml, dataInfo) {
236         /*
237          *  Need to get the full path of the xml file, or the Tiny XML can't find the xml at IOS
238          */
239         var xmlStr = cc.loader.getRes(xml);
240         if (!xmlStr) throw "Please load the resource first : " + xml;
241         var skeletonXML = cc.saxParser.parse(xmlStr);
242         var skeleton = skeletonXML.documentElement;
243         if (skeleton) {
244             this.addDataFromCache(skeleton, dataInfo);
245         }
246     },
247 
248     addDataFromCache: function (skeleton, dataInfo) {
249         if (!skeleton) {
250             cc.log("XML error  or  XML is empty.");
251             return;
252         }
253         dataInfo.flashToolVersion = parseFloat(skeleton.getAttribute(ccs.CONST_VERSION));
254         var armaturesXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_ARMATURES + " >  " + ccs.CONST_ARMATURE + "");
255         var armatureDataManager = ccs.armatureDataManager;
256         for (var i = 0; i < armaturesXML.length; i++) {
257             var armatureData = this.decodeArmature(armaturesXML[i], dataInfo);
258             armatureDataManager.addArmatureData(armatureData.name, armatureData, dataInfo.filename);
259         }
260 
261         var animationsXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_ANIMATIONS + " >  " + ccs.CONST_ANIMATION + "");
262         for (var i = 0; i < animationsXML.length; i++) {
263             var animationData = this.decodeAnimation(animationsXML[i], dataInfo);
264             armatureDataManager.addAnimationData(animationData.name, animationData, dataInfo.filename);
265         }
266 
267         var texturesXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_TEXTURE_ATLAS + " >  " + ccs.CONST_SUB_TEXTURE + "");
268         for (var i = 0; i < texturesXML.length; i++) {
269             var textureData = this.decodeTexture(texturesXML[i], dataInfo);
270             armatureDataManager.addTextureData(textureData.name, textureData, dataInfo.filename);
271         }
272         skeleton = null;
273     },
274 
275     decodeArmature: function (armatureXML, dataInfo) {
276         var name = armatureXML.getAttribute(ccs.CONST_A_NAME);
277         var armatureData = new ccs.ArmatureData();
278         armatureData.name = name;
279 
280         var bonesXML = armatureXML.querySelectorAll(ccs.CONST_ARMATURE + " > " + ccs.CONST_BONE);
281 
282         for (var i = 0; i < bonesXML.length; i++) {
283             var boneXML = bonesXML[i];
284             var parentName = boneXML.getAttribute(ccs.CONST_A_PARENT);
285             var parentXML = null;
286             if (parentName) {
287                 //parentXML = armatureXML.querySelectorAll(ccs.CONST_ARMATURE+" > "+ccs.CONST_BONE);
288                 for (var j = 0; j < bonesXML.length; j++) {
289                     parentXML = bonesXML[j];
290                     if (parentName == bonesXML[j].getAttribute(ccs.CONST_A_NAME)) {
291                         //todo
292                         break;
293                     }
294                 }
295             }
296             var boneData = this.decodeBone(boneXML, parentXML, dataInfo);
297             armatureData.addBoneData(boneData);
298         }
299         return armatureData;
300     },
301 
302     decodeBone: function (boneXML, parentXML, dataInfo) {
303 
304         var name = boneXML.getAttribute(ccs.CONST_A_NAME);
305         if (name == "") {
306             return;
307         }
308         var boneData = new ccs.BoneData();
309         boneData.name = name;
310         boneData.parentName = boneXML.getAttribute(ccs.CONST_A_PARENT) || "";
311         boneData.zOrder = parseInt(boneXML.getAttribute(ccs.CONST_A_Z)) || 0;
312 
313         var displaysXML = boneXML.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_DISPLAY);
314 
315         var displayXML;
316         for (var i = 0; i < displaysXML.length; i++) {
317             displayXML = displaysXML[i];
318             var displayData = this.decodeBoneDisplay(displayXML, dataInfo);
319             boneData.addDisplayData(displayData);
320         }
321         return boneData;
322     },
323     decodeBoneDisplay: function (displayXML, dataInfo) {
324         var isArmature = parseFloat(displayXML.getAttribute(ccs.CONST_A_IS_ARMATURE)) || 0;
325         var displayData = null;
326 
327         if (isArmature == 1) {
328             displayData = new ccs.ArmatureDisplayData();
329             displayData.displayType = ccs.DISPLAY_TYPE_ARMATURE;
330         }
331         else {
332             displayData = new ccs.SpriteDisplayData();
333             displayData.displayType = ccs.DISPLAY_TYPE_SPRITE;
334         }
335         var displayName = displayXML.getAttribute(ccs.CONST_A_NAME) || "";
336         if (displayName) {
337             displayData.displayName = displayName;
338         }
339         return displayData;
340     },
341 
342 
343     decodeAnimation: function (animationXML, dataInfo) {
344         var name = animationXML.getAttribute(ccs.CONST_A_NAME);
345         var aniData = new ccs.AnimationData();
346         var armatureData = ccs.armatureDataManager.getArmatureData(name);
347         aniData.name = name;
348 
349         var movementsXML = animationXML.querySelectorAll(ccs.CONST_ANIMATION + " > " + ccs.CONST_MOVEMENT);
350         var movementXML = null;
351         for (var i = 0; i < movementsXML.length; i++) {
352             movementXML = movementsXML[i];
353             var movementData = this.decodeMovement(movementXML, armatureData, dataInfo);
354             aniData.addMovement(movementData);
355         }
356         return aniData;
357     },
358 
359     decodeMovement: function (movementXML, armatureData, dataInfo) {
360         var movName = movementXML.getAttribute(ccs.CONST_A_NAME);
361         var movementData = new ccs.MovementData();
362         movementData.name = movName;
363         var duration, durationTo, durationTween, loop = 0, tweenEasing = 0;
364 
365         duration = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION)) || 0;
366         movementData.duration = duration;
367 
368         durationTo = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION_TO)) || 0;
369         movementData.durationTo = durationTo;
370 
371         durationTween = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION_TWEEN)) || 0;
372         movementData.durationTween = durationTween;
373 
374         loop = movementXML.getAttribute(ccs.CONST_A_LOOP);
375         movementData.loop = loop ? Boolean(parseFloat(loop)) : true;
376 
377         var easing = movementXML.getAttribute(ccs.CONST_A_TWEEN_EASING);
378         if (easing) {
379             if (easing != ccs.CONST_FL_NAN) {
380                 tweenEasing = parseFloat(easing) || 0;
381                 movementData.tweenEasing = tweenEasing == 2 ? ccs.TweenType.sineEaseInOut : tweenEasing;
382             } else {
383                 movementData.tweenEasing = ccs.TweenType.linear;
384             }
385         }
386 
387         var movBonesXml = movementXML.querySelectorAll(ccs.CONST_MOVEMENT + " > " + ccs.CONST_BONE);
388         var movBoneXml = null;
389         for (var i = 0; i < movBonesXml.length; i++) {
390             movBoneXml = movBonesXml[i];
391             var boneName = movBoneXml.getAttribute(ccs.CONST_A_NAME);
392 
393             if (movementData.getMovementBoneData(boneName)) {
394                 continue;
395             }
396 
397             var boneData = armatureData.getBoneData(boneName);
398             var parentName = boneData.parentName;
399 
400             var parentXML = null;
401             if (parentName != "") {
402                 for (var j = 0; j < movBonesXml.length; j++) {
403                     parentXML = movBonesXml[j];
404                     if (parentName == parentXML.getAttribute(ccs.CONST_A_NAME)) {
405                         break;
406                     }
407                 }
408             }
409             var moveBoneData = this.decodeMovementBone(movBoneXml, parentXML, boneData, dataInfo);
410             movementData.addMovementBoneData(moveBoneData);
411         }
412         return movementData;
413     },
414 
415     decodeMovementBone: function (movBoneXml, parentXml, boneData, dataInfo) {
416         var movBoneData = new ccs.MovementBoneData();
417         var scale, delay;
418 
419         if (movBoneXml) {
420             scale = parseFloat(movBoneXml.getAttribute(ccs.CONST_A_MOVEMENT_SCALE)) || 0;
421             movBoneData.scale = scale;
422 
423             delay = parseFloat(movBoneXml.getAttribute(ccs.CONST_A_MOVEMENT_DELAY)) || 0;
424             if (delay > 0) {
425                 delay -= 1;
426             }
427             movBoneData.delay = delay;
428         }
429 
430         var length = 0;
431         var parentTotalDuration = 0;
432         var currentDuration = 0;
433         var parentFrameXML = null;
434         var parentXMLList = [];
435 
436         //*  get the parent frame xml list, we need get the origin data
437         if (parentXml != null) {
438             var parentFramesXML = parentXml.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_FRAME);
439             for (var i = 0; i < parentFramesXML.length; i++) {
440                 parentXMLList.push(parentFramesXML[i]);
441             }
442             length = parentXMLList.length;
443         }
444 
445 
446         var totalDuration = 0;
447 
448         var name = movBoneXml.getAttribute(ccs.CONST_A_NAME);
449         movBoneData.name = name;
450         var framesXML = movBoneXml.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_FRAME);
451         var j = 0;
452         for (var ii = 0; ii < framesXML.length; ii++) {
453             var frameXML = framesXML[ii];
454             if (parentXml) {
455                 //*  in this loop we get the corresponding parent frame xml
456                 while (j < length && (parentFrameXML ? (totalDuration < parentTotalDuration || totalDuration >= parentTotalDuration + currentDuration) : true)) {
457                     parentFrameXML = parentXMLList[j];
458                     parentTotalDuration += currentDuration;
459                     currentDuration = parseFloat(parentFrameXML.getAttribute(ccs.CONST_A_DURATION));
460                     j++;
461                 }
462             }
463             var frameData = this.decodeFrame(frameXML, parentFrameXML, boneData, dataInfo);
464             movBoneData.addFrameData(frameData);
465             frameData.frameID = totalDuration;
466             totalDuration += frameData.duration;
467             movBoneData.duration = totalDuration;
468         }
469 
470         //Change rotation range from (-180 -- 180) to (-infinity -- infinity)
471         var frames = movBoneData.frameList;
472         var pi = Math.PI;
473         for (var i = frames.length - 1; i >= 0; i--) {
474             if (i > 0) {
475                 var difSkewX = frames[i].skewX - frames[i - 1].skewX;
476                 var difSkewY = frames[i].skewY - frames[i - 1].skewY;
477 
478                 if (difSkewX < -pi || difSkewX > pi) {
479                     frames[i - 1].skewX = difSkewX < 0 ? frames[i - 1].skewX - 2 * pi : frames[i - 1].skewX + 2 * pi;
480                 }
481 
482                 if (difSkewY < -pi || difSkewY > pi) {
483                     frames[i - 1].skewY = difSkewY < 0 ? frames[i - 1].skewY - 2 * pi : frames[i - 1].skewY + 2 * pi;
484                 }
485             }
486         }
487 
488         if (movBoneData.frameList.length > 0) {
489             var frameData = new ccs.FrameData();
490             frameData.copy(movBoneData.frameList[movBoneData.frameList.length - 1]);
491             frameData.frameID = movBoneData.duration;
492             movBoneData.addFrameData(frameData);
493         }
494         return movBoneData;
495     },
496     decodeFrame: function (frameXML, parentFrameXml, boneData, dataInfo) {
497         var frameData = new ccs.FrameData();
498         frameData.movement = frameXML.getAttribute(ccs.CONST_A_MOVEMENT) || "";
499         frameData.event = frameXML.getAttribute(ccs.CONST_A_EVENT) || "";
500         frameData.blendType = parseInt(frameXML.getAttribute(ccs.CONST_A_BLEND_TYPE)) || ccs.BLEND_TYPE_NORMAL;
501 
502         var blendFunc = frameData.blendFunc;
503         switch (frameData.blendType) {
504             case ccs.BLEND_TYPE_NORMAL:
505                 blendFunc.src = cc.BLEND_SRC;
506                 blendFunc.dst = cc.BLEND_DST;
507                 break;
508             case ccs.BLEND_TYPE_ADD:
509                 blendFunc.src = cc.SRC_ALPHA;
510                 blendFunc.dst = cc.ONE;
511                 break;
512             case ccs.BLEND_TYPE_MULTIPLY:
513                 blendFunc.src = cc.ONE_MINUS_SRC_ALPHA;
514                 blendFunc.dst = cc.ONE_MINUS_DST_COLOR;
515                 break;
516             case ccs.BLEND_TYPE_SCREEN:
517                 blendFunc.src = cc.ONE;
518                 blendFunc.dst = cc.ONE_MINUS_DST_COLOR;
519                 break;
520             default:
521                 break;
522         }
523 
524         frameData.sound = frameXML.getAttribute(ccs.CONST_A_SOUND) || "";
525         frameData.soundEffect = frameXML.getAttribute(ccs.CONST_A_SOUND_EFFECT) || "";
526 
527         var isTween = frameXML.getAttribute(ccs.CONST_A_TWEEN_FRAME);
528         if(isTween == null)
529             isTween = true;
530         frameData.isTween = Boolean(isTween);
531 
532         if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) {
533             frameData.x = parseFloat(frameXML.getAttribute(ccs.CONST_A_COCOS2DX_X)) || 0;
534             frameData.y = -parseFloat(frameXML.getAttribute(ccs.CONST_A_COCOS2DX_Y)) || 0;
535         }
536         else {
537             frameData.x = parseFloat(frameXML.getAttribute(ccs.CONST_A_X)) || 0;
538             frameData.y = -parseFloat(frameXML.getAttribute(ccs.CONST_A_Y)) || 0;
539         }
540         frameData.x *= this._positionReadScale;
541         frameData.y *= this._positionReadScale;
542         frameData.scaleX = parseFloat(frameXML.getAttribute(ccs.CONST_A_SCALE_X)) || 0;
543         frameData.scaleY = parseFloat(frameXML.getAttribute(ccs.CONST_A_SCALE_Y)) || 0;
544         frameData.skewX = cc.degreesToRadians(parseFloat(frameXML.getAttribute(ccs.CONST_A_SKEW_X)) || 0);
545         frameData.skewY = cc.degreesToRadians(-parseFloat(frameXML.getAttribute(ccs.CONST_A_SKEW_Y)) || 0);
546         frameData.duration = parseFloat(frameXML.getAttribute(ccs.CONST_A_DURATION)) || 0;
547         frameData.displayIndex = parseFloat(frameXML.getAttribute(ccs.CONST_A_DISPLAY_INDEX)) || 0;
548         frameData.zOrder = parseFloat(frameXML.getAttribute(ccs.CONST_A_Z)) || 0;
549         frameData.tweenRotate = parseFloat(frameXML.getAttribute(ccs.CONST_A_TWEEN_ROTATION)) || 0;
550 
551         var colorTransformXMLList = frameXML.querySelectorAll(ccs.CONST_FRAME + " > " + ccs.CONST_A_COLOR_TRANSFORM);
552         if (colorTransformXMLList.length > 0) {
553             var colorTransformXML = colorTransformXMLList[0];
554             var alpha = 0, red = 0, green = 0, blue = 0;
555             var alphaOffset = 0, redOffset = 0, greenOffset = 0, blueOffset = 100;
556 
557             alpha = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_ALPHA)) || alpha;
558             red = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_RED)) || red;
559             green = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_GREEN)) || green;
560             blue = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_BLUE)) || blue;
561 
562             var str_alphaOffset = colorTransformXML.getAttribute(ccs.CONST_A_ALPHA_OFFSET);
563             if (str_alphaOffset) {
564                 alphaOffset = parseFloat(str_alphaOffset);
565             }
566             var str_redOffset = colorTransformXML.getAttribute(ccs.CONST_A_RED_OFFSET);
567             if (str_redOffset) {
568                 redOffset = parseFloat(str_redOffset);
569             }
570             var str_greenOffset = colorTransformXML.getAttribute(ccs.CONST_A_GREEN_OFFSET);
571             if (str_redOffset) {
572                 greenOffset = parseFloat(str_greenOffset);
573             }
574             var str_blueOffset = colorTransformXML.getAttribute(ccs.CONST_A_BLUE_OFFSET);
575             if (str_blueOffset) {
576                 blueOffset = parseFloat(str_blueOffset);
577             }
578 
579             frameData.a = 2.55 * alphaOffset + alpha;
580             frameData.r = 2.55 * redOffset + red;
581             frameData.g = 2.55 * greenOffset + green;
582             frameData.b = 2.55 * blueOffset + blue;
583 
584             frameData.isUseColorInfo = true;
585         }
586         if (frameData.displayIndex == -1) {
587             frameData.a = 0;
588         }
589 
590         var tweenEasing = frameXML.getAttribute(ccs.CONST_A_TWEEN_EASING);
591         if (tweenEasing) {
592             if (tweenEasing != ccs.CONST_FL_NAN) {
593                 frameData.tweenEasing = tweenEasing == 2 ? ccs.TweenType.sineEaseInOut : tweenEasing;
594             } else {
595                 frameData.tweenEasing = ccs.TweenType.linear;
596             }
597         }
598 
599         if (parentFrameXml) {
600             //*  recalculate frame data from parent frame data, use for translate matrix
601             var helpNode = new ccs.BaseData();
602             if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) {
603                 helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_X)) || 0;
604                 helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_Y)) || 0;
605             }
606             else {
607                 helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_X)) || 0;
608                 helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_Y)) || 0;
609             }
610             helpNode.skewX = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_X)) || 0;
611             helpNode.skewY = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_Y)) || 0;
612 
613             helpNode.y = -helpNode.y;
614             helpNode.skewX = cc.degreesToRadians(helpNode.skewX);
615             helpNode.skewY = cc.degreesToRadians(-helpNode.skewY);
616             ccs.TransformHelp.transformFromParent(frameData, helpNode);
617         }
618         return frameData;
619     },
620 
621     decodeTexture: function (textureXML, dataInfo) {
622         var textureData = new ccs.TextureData();
623         if (textureXML.getAttribute(ccs.CONST_A_NAME)) {
624             textureData.name = textureXML.getAttribute(ccs.CONST_A_NAME);
625         }
626         var px, py, width, height = 0;
627         if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) {
628             px = parseFloat(textureXML.getAttribute(ccs.CONST_A_COCOS2D_PIVOT_X)) || 0;
629             py = parseFloat(textureXML.getAttribute(ccs.CONST_A_COCOS2D_PIVOT_Y)) || 0;
630         }
631         else {
632             px = parseFloat(textureXML.getAttribute(ccs.CONST_A_PIVOT_X)) || 0;
633             py = parseFloat(textureXML.getAttribute(ccs.CONST_A_PIVOT_Y)) || 0;
634         }
635         width = parseFloat(textureXML.getAttribute(ccs.CONST_A_WIDTH)) || 0;
636         height = parseFloat(textureXML.getAttribute(ccs.CONST_A_HEIGHT)) || 0;
637 
638         var anchorPointX = px / width;
639         var anchorPointY = (height - py) / height;
640 
641         textureData.pivotX = anchorPointX;
642         textureData.pivotY = anchorPointY;
643 
644         var contoursXML = textureXML.querySelectorAll(ccs.CONST_SUB_TEXTURE + " > " + ccs.CONST_CONTOUR);
645         for (var i = 0; i < contoursXML.length; i++) {
646             this.decodeContour(contoursXML[i], dataInfo);
647         }
648         return textureData;
649     },
650 
651     decodeContour: function (contourXML, dataInfo) {
652         var contourData = new ccs.ContourData();
653         var vertexDatasXML = contourXML.querySelectorAll(ccs.CONST_CONTOUR + " > " + ccs.CONST_CONTOUR_VERTEX);
654         var vertexDataXML;
655         for (var i = 0; i < vertexDatasXML.length; i++) {
656             vertexDataXML = vertexDatasXML[i];
657             var vertex = cc.p(0, 0);
658             vertex.x = parseFloat(vertexDataXML.getAttribute(ccs.CONST_A_X)) || 0;
659             vertex.y = parseFloat(vertexDataXML.getAttribute(ccs.CONST_A_Y)) || 0;
660             //vertex.y = - vertex.y;//todo
661             contourData.vertexList.push(vertex);
662         }
663         return contourData;
664 
665     },
666 
667     addDataFromJson: function (filePath, dataInfo, isLoadSpriteFrame) {
668         var fileContent = cc.loader.getRes(filePath);
669         this.addDataFromJsonCache(fileContent, dataInfo, isLoadSpriteFrame);
670     },
671     addDataFromJsonCache: function (dic, dataInfo, isLoadSpriteFrame) {
672         dataInfo.contentScale = dic[ccs.CONST_CONTENT_SCALE] || 1;
673         var armatureDataArr = dic[ccs.CONST_ARMATURE_DATA] || [];
674         var armatureData;
675         for (var i = 0; i < armatureDataArr.length; i++) {
676             armatureData = this.decodeArmatureFromJSON(armatureDataArr[i], dataInfo);
677             ccs.armatureDataManager.addArmatureData(armatureData.name, armatureData, dataInfo.filename);
678         }
679 
680         var animationDataArr = dic[ccs.CONST_ANIMATION_DATA] || [];
681         var animationData;
682         for (var i = 0; i < animationDataArr.length; i++) {
683             animationData = this.decodeAnimationFromJson(animationDataArr[i], dataInfo);
684             ccs.armatureDataManager.addAnimationData(animationData.name, animationData, dataInfo.filename);
685         }
686 
687         var textureDataArr = dic[ccs.CONST_TEXTURE_DATA] || [];
688         var textureData;
689         for (var i = 0; i < textureDataArr.length; i++) {
690             textureData = this.decodeTextureFromJson(textureDataArr[i], dataInfo);
691             ccs.armatureDataManager.addTextureData(textureData.name, textureData, dataInfo.filename);
692         }
693 
694         if (isLoadSpriteFrame) {
695             var configFiles = dic[ccs.CONST_CONFIG_FILE_PATH] || [];
696             var locFilePath, locPos, locPlistPath, locImagePath;
697             for (var i = 0; i < configFiles.length; i++) {
698                 locFilePath = configFiles[i];
699                 locPos = locFilePath.lastIndexOf(".");
700                 locFilePath = locFilePath.substring(0, locPos);
701                 locPlistPath = dataInfo.basefilePath + locFilePath + ".plist";
702                 locImagePath = dataInfo.basefilePath + locFilePath + ".png";
703                 ccs.armatureDataManager.addSpriteFrameFromFile(locPlistPath, locImagePath, dataInfo.filename);
704             }
705         }
706 
707         armatureData = null;
708         animationData = null;
709     },
710 
711     decodeArmatureFromJSON: function (json, dataInfo) {
712         var armatureData = new ccs.ArmatureData();
713 
714         var name = json[ccs.CONST_A_NAME];
715         if (name) {
716             armatureData.name = name;
717         }
718 
719         dataInfo.cocoStudioVersion = armatureData.dataVersion = json[ccs.CONST_VERSION] || 0.1;
720 
721         var boneDataList = json[ccs.CONST_BONE_DATA];
722         for (var i = 0; i < boneDataList.length; i++) {
723             armatureData.addBoneData(this.decodeBoneFromJson(boneDataList[i], dataInfo));
724         }
725         return armatureData;
726     },
727 
728     decodeBoneFromJson: function (json, dataInfo) {
729         var boneData = new ccs.BoneData();
730         this.decodeNodeFromJson(boneData, json, dataInfo);
731         boneData.name = json[ccs.CONST_A_NAME] || "";
732         boneData.parentName = json[ccs.CONST_A_PARENT] || "";
733         var displayDataList = json[ccs.CONST_DISPLAY_DATA] || [];
734         for (var i = 0; i < displayDataList.length; i++) {
735             var locDisplayData = this.decodeBoneDisplayFromJson(displayDataList[i], dataInfo);
736             boneData.addDisplayData(locDisplayData);
737         }
738         return boneData;
739     },
740 
741     decodeBoneDisplayFromJson: function (json, dataInfo) {
742         var displayType = json[ccs.CONST_A_DISPLAY_TYPE] || ccs.DISPLAY_TYPE_SPRITE;
743         var displayData = null;
744         switch (displayType) {
745             case ccs.DISPLAY_TYPE_SPRITE:
746                 displayData = new ccs.SpriteDisplayData();
747                 displayData.displayName = json[ccs.CONST_A_NAME] || "";
748 
749                 var dicArray = json[ccs.CONST_SKIN_DATA] || [];
750                 var dic = dicArray[0];
751                 if (dic) {
752                     var skinData = displayData.skinData;
753                     skinData.x = (dic[ccs.CONST_A_X] || 0) * this._positionReadScale;
754                     skinData.y = (dic[ccs.CONST_A_Y] || 0) * this._positionReadScale;
755                     if (dic[ccs.CONST_A_SCALE_X] !== undefined) {
756                         skinData.scaleX = dic[ccs.CONST_A_SCALE_X];
757                     }
758                     if (dic[ccs.CONST_A_SCALE_Y] !== undefined) {
759                         skinData.scaleY = dic[ccs.CONST_A_SCALE_Y];
760                     }
761                     skinData.skewX = dic[ccs.CONST_A_SKEW_X] || 0;
762                     skinData.skewY = dic[ccs.CONST_A_SKEW_Y] || 0;
763 
764                     skinData.x *= dataInfo.contentScale;
765                     skinData.y *= dataInfo.contentScale;
766                     dic = null;
767                 }
768                 break;
769             case ccs.DISPLAY_TYPE_ARMATURE:
770                 displayData = new ccs.ArmatureDisplayData();
771                 displayData.displayName = json[ccs.CONST_A_NAME] || "";
772                 break;
773             case ccs.DISPLAY_TYPE_PARTICLE:
774                 displayData = new ccs.ParticleDisplayData();
775                 displayData.displayName = dataInfo.basefilePath + json[ccs.CONST_A_PLIST] || "";
776                 break;
777             default:
778                 displayData = new ccs.SpriteDisplayData();
779                 break;
780         }
781 
782         displayData.displayType = displayType;
783 
784         return displayData;
785     },
786 
787     decodeAnimationFromJson: function (json, dataInfo) {
788         var aniData = new ccs.AnimationData();
789         aniData.name = json[ccs.CONST_A_NAME] || "";
790         var movementDataList = json[ccs.CONST_MOVEMENT_DATA] || [];
791         for (var i = 0; i < movementDataList.length; i++) {
792             var locMovementData = this.decodeMovementFromJson(movementDataList[i], dataInfo);
793             aniData.addMovement(locMovementData);
794         }
795         return aniData;
796     },
797 
798     decodeMovementFromJson: function (json, dataInfo) {
799         var movementData = new ccs.MovementData();
800 
801         movementData.loop = json[ccs.CONST_A_LOOP] || false;
802         movementData.durationTween = json[ccs.CONST_A_DURATION_TWEEN] || 0;
803         movementData.durationTo = json[ccs.CONST_A_DURATION_TO] || 0;
804         movementData.duration = json[ccs.CONST_A_DURATION] || 0;
805         if (json[ccs.CONST_A_MOVEMENT_SCALE] !== undefined) {
806             movementData.scale = json[ccs.CONST_A_MOVEMENT_SCALE]
807         }
808         movementData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.linear;
809         movementData.name = json[ccs.CONST_A_NAME] || "";
810 
811         var movementBoneList = json[ccs.CONST_MOVEMENT_BONE_DATA] || [];
812         for (var i = 0; i < movementBoneList.length; i++) {
813             var locMovementBoneData = this.decodeMovementBoneFromJson(movementBoneList[i], dataInfo);
814             movementData.addMovementBoneData(locMovementBoneData);
815         }
816         return movementData;
817     },
818 
819     decodeMovementBoneFromJson: function (json, dataInfo) {
820         var movementBoneData = new ccs.MovementBoneData();
821         movementBoneData.delay = json[ccs.CONST_A_MOVEMENT_DELAY] || 0;
822         if (json[ccs.CONST_A_MOVEMENT_SCALE] !== undefined) {
823             movementBoneData.scale = json[ccs.CONST_A_MOVEMENT_SCALE];
824         }
825 
826         movementBoneData.name = json[ccs.CONST_A_NAME] || "";
827         var frameDataList = json[ccs.CONST_FRAME_DATA] || [];
828         for (var i = 0; i < frameDataList.length; i++) {
829             var frameData = this.decodeFrameFromJson(frameDataList[i], dataInfo);
830             movementBoneData.addFrameData(frameData);
831             if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) {
832                 frameData.frameID = movementBoneData.duration;
833                 movementBoneData.duration += frameData.duration;
834             }
835         }
836 
837         if (dataInfo.cocoStudioVersion < ccs.VERSION_CHANGE_ROTATION_RANGE) {
838             //! Change rotation range from (-180 -- 180) to (-infinity -- infinity)
839             var frames = movementBoneData.frameList;
840             var pi = Math.PI;
841             for (var i = frames.length - 1; i >= 0; i--) {
842                 if (i > 0) {
843                     var difSkewX = frames[i].skewX - frames[i - 1].skewX;
844                     var difSkewY = frames[i].skewY - frames[i - 1].skewY;
845 
846                     if (difSkewX < -pi || difSkewX > pi) {
847                         frames[i - 1].skewX = difSkewX < 0 ? frames[i - 1].skewX - 2 * pi : frames[i - 1].skewX + 2 * pi;
848                     }
849 
850                     if (difSkewY < -pi || difSkewY > pi) {
851                         frames[i - 1].skewY = difSkewY < 0 ? frames[i - 1].skewY - 2 * pi : frames[i - 1].skewY + 2 * pi;
852                     }
853                 }
854             }
855         }
856 
857         if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) {
858             if (movementBoneData.frameList.length > 0) {
859                 var frameData = new ccs.FrameData();
860                 frameData.copy(movementBoneData.frameList[movementBoneData.frameList.length - 1]);
861                 movementBoneData.addFrameData(frameData);
862                 frameData.frameID = movementBoneData.duration;
863             }
864         }
865         return movementBoneData;
866     },
867 
868     decodeFrameFromJson: function (json, dataInfo) {
869         var frameData = new ccs.FrameData();
870         this.decodeNodeFromJson(frameData, json, dataInfo);
871         frameData.duration = json[ccs.CONST_A_DURATION] || 0;
872         frameData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.linear;
873         frameData.displayIndex = json[ccs.CONST_A_DISPLAY_INDEX] || 0;
874 
875         var bd_src = json[ccs.CONST_A_BLEND_SRC] || cc.BLEND_SRC;
876         var bd_dst = json[ccs.CONST_A_BLEND_DST] || cc.BLEND_DST;
877         frameData.blendFunc.src = bd_src;
878         frameData.blendFunc.dst = bd_dst;
879 
880         frameData.event = json[ccs.CONST_A_EVENT] || null;
881         if (json[ccs.CONST_A_TWEEN_FRAME] !== undefined) {
882             frameData.isTween = json[ccs.CONST_A_TWEEN_FRAME]
883         }
884         if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED)
885             frameData.duration = json[ccs.CONST_A_DURATION] || 0;
886         else
887             frameData.frameID = json[ccs.CONST_A_FRAME_INDEX] || 0;
888 
889         var twEPs = json[ccs.CONST_A_EASING_PARAM] || [];
890         for (var i = 0; i < twEPs.length; i++) {
891             var twEP = twEPs[i];
892             frameData.easingParams[i] = twEP;
893         }
894 
895         return frameData;
896     },
897 
898     decodeTextureFromJson: function (json) {
899         var textureData = new ccs.TextureData();
900         textureData.name = json[ccs.CONST_A_NAME] || "";
901         textureData.width = json[ccs.CONST_A_WIDTH] || 0;
902         textureData.height = json[ccs.CONST_A_HEIGHT] || 0;
903         textureData.pivotX = json[ccs.CONST_A_PIVOT_X] || 0;
904         textureData.pivotY = json[ccs.CONST_A_PIVOT_Y] || 0;
905 
906         var contourDataList = json[ccs.CONST_CONTOUR_DATA] || [];
907         for (var i = 0; i < contourDataList.length; i++) {
908             var locContourData = this.decodeContourFromJson(contourDataList[i]);
909             textureData.contourDataList.push(locContourData);
910         }
911         return textureData;
912     },
913 
914     decodeContourFromJson: function (json) {
915         var contourData = new ccs.ContourData();
916         var vertexPointList = json[ccs.CONST_VERTEX_POINT] || [];
917         for (var i = 0; i < vertexPointList.length; i++) {
918             var dic = vertexPointList[i];
919             var vertex = cc.p(0, 0);
920             vertex.x = dic[ccs.CONST_A_X] || 0;
921             vertex.y = dic[ccs.CONST_A_Y] || 0;
922             contourData.vertexList.push(vertex);
923         }
924         return contourData;
925     },
926 
927     decodeNodeFromJson: function (node, json, dataInfo) {
928         node.x = json[ccs.CONST_A_X] || 0;
929         node.y = json[ccs.CONST_A_Y] || 0;
930 
931         node.x *= dataInfo.contentScale;
932         node.y *= dataInfo.contentScale;
933 
934         node.zOrder = json[ccs.CONST_A_Z] || 0;
935 
936         node.skewX = json[ccs.CONST_A_SKEW_X] || 0;
937         node.skewY = json[ccs.CONST_A_SKEW_Y] || 0;
938         if (json[ccs.CONST_A_SCALE_X] !== undefined) {
939             node.scaleX = json[ccs.CONST_A_SCALE_X];
940         }
941         if (json[ccs.CONST_A_SCALE_Y] !== undefined) {
942             node.scaleY = json[ccs.CONST_A_SCALE_Y];
943         }
944 
945         var colorDic = json[ccs.CONST_COLOR_INFO] || null;
946         if (colorDic) {
947             //compatible old version
948             if (dataInfo.cocoStudioVersion < ccs.VERSION_COLOR_READING) {
949                 colorDic = colorDic[0];
950             }
951             node.a = colorDic[ccs.CONST_A_ALPHA];
952             node.r = colorDic[ccs.CONST_A_RED];
953             node.g = colorDic[ccs.CONST_A_GREEN];
954             node.b = colorDic[ccs.CONST_A_BLUE];
955             node.isUseColorInfo = true;
956             delete colorDic;
957         }
958     },
959 
960     removeConfigFile: function (configFile) {
961         cc.arrayRemoveObject(this._configFileList, configFile);
962     }
963 };