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