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  * CocoStudio data reader helper
148  * @namespace
149  * @name ccs.dataReaderHelper
150  */
151 ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{
152     _configFileList: [],
153     _flashToolVersion: ccs.CONST_VERSION_2_0,
154     _cocoStudioVersion: ccs.CONST_VERSION_COMBINED,
155     _positionReadScale: 1,
156     _asyncRefCount: 0,
157     _asyncRefTotalCount: 0,
158 
159     setPositionReadScale: function (scale) {
160         this._positionReadScale = scale;
161     },
162 
163     getPositionReadScale: function () {
164         return this._positionReadScale;
165     },
166 
167     clear: function () {
168         this._configFileList = [];
169         this._asyncRefCount = 0;
170         this._asyncRefTotalCount = 0;
171     },
172 
173     addDataFromFile: function (filePath, isLoadSpriteFrame) {
174         if (this._configFileList.indexOf(filePath) != -1) {
175             return;
176         }
177         this._configFileList.push(filePath);
178 
179         this._initBaseFilePath(filePath);
180 
181         var str = cc.path.extname(filePath).toLowerCase();
182 
183         var dataInfo = new ccs.DataInfo();
184         dataInfo.filename = filePath;
185         dataInfo.basefilePath = this._initBaseFilePath(filePath);
186         if (str == ".xml") {
187             this.addDataFromXML(filePath, dataInfo);
188         }
189         else if (str == ".json" || str == ".exportjson") {
190             this.addDataFromJson(filePath, dataInfo, isLoadSpriteFrame);
191         }
192     },
193 
194     addDataFromFileAsync: function (filePath, target, selector, isLoadSpriteFrame) {
195         if (this._configFileList.indexOf(filePath) != -1) {
196             if (target && selector) {
197                 if (this._asyncRefTotalCount == 0 && this._asyncRefCount == 0)
198                     this._asyncCallBack(target, selector, 1);
199                 else
200                     this._asyncCallBack(target, selector, (this._asyncRefTotalCount - this._asyncRefCount) / this._asyncRefTotalCount);
201             }
202             return;
203         }
204         this._asyncRefTotalCount++;
205         this._asyncRefCount++;
206         var self = this;
207         var fun = function () {
208             self.addDataFromFile(filePath, isLoadSpriteFrame);
209             self._asyncRefCount--;
210             self._asyncCallBack(target, selector, (self._asyncRefTotalCount - self._asyncRefCount) / self._asyncRefTotalCount);
211         };
212         cc.director.getScheduler().scheduleCallbackForTarget(this, fun, 0.1, false);
213     },
214 
215     _asyncCallBack: function (target, selector, percent) {
216         if (target && (typeof(selector) == "string")) {
217             target[selector](percent);
218         } else if (target && (typeof(selector) == "function")) {
219             selector.call(target, percent);
220         }
221     },
222     /**
223      * find the base file path
224      * @param filePath
225      * @returns {String}
226      * @private
227      */
228     _initBaseFilePath: function (filePath) {
229         var path = filePath;
230         var pos = path.lastIndexOf("/");
231         if (pos > -1)
232             path = path.substr(0, pos + 1);
233         else
234             path = "";
235         return path;
236     },
237 
238     addDataFromXML: function (xml, dataInfo) {
239         /*
240          *  Need to get the full path of the xml file, or the Tiny XML can't find the xml at IOS
241          */
242         var xmlStr = cc.loader.getRes(xml);
243         if (!xmlStr) throw "Please load the resource first : " + xml;
244         var skeletonXML = cc.saxParser.parse(xmlStr);
245         var skeleton = skeletonXML.documentElement;
246         if (skeleton) {
247             this.addDataFromCache(skeleton, dataInfo);
248         }
249     },
250 
251     addDataFromCache: function (skeleton, dataInfo) {
252         if (!skeleton) {
253             cc.log("XML error  or  XML is empty.");
254             return;
255         }
256         dataInfo.flashToolVersion = parseFloat(skeleton.getAttribute(ccs.CONST_VERSION));
257         var armaturesXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_ARMATURES + " >  " + ccs.CONST_ARMATURE + "");
258         var armatureDataManager = ccs.armatureDataManager;
259         for (var i = 0; i < armaturesXML.length; i++) {
260             var armatureData = this.decodeArmature(armaturesXML[i], dataInfo);
261             armatureDataManager.addArmatureData(armatureData.name, armatureData, dataInfo.filename);
262         }
263 
264         var animationsXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_ANIMATIONS + " >  " + ccs.CONST_ANIMATION + "");
265         for (var i = 0; i < animationsXML.length; i++) {
266             var animationData = this.decodeAnimation(animationsXML[i], dataInfo);
267             armatureDataManager.addAnimationData(animationData.name, animationData, dataInfo.filename);
268         }
269 
270         var texturesXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_TEXTURE_ATLAS + " >  " + ccs.CONST_SUB_TEXTURE + "");
271         for (var i = 0; i < texturesXML.length; i++) {
272             var textureData = this.decodeTexture(texturesXML[i], dataInfo);
273             armatureDataManager.addTextureData(textureData.name, textureData, dataInfo.filename);
274         }
275         skeleton = null;
276     },
277 
278     decodeArmature: function (armatureXML, dataInfo) {
279         var name = armatureXML.getAttribute(ccs.CONST_A_NAME);
280         var armatureData = new ccs.ArmatureData();
281         armatureData.name = name;
282 
283         var bonesXML = armatureXML.querySelectorAll(ccs.CONST_ARMATURE + " > " + ccs.CONST_BONE);
284 
285         for (var i = 0; i < bonesXML.length; i++) {
286             var boneXML = bonesXML[i];
287             var parentName = boneXML.getAttribute(ccs.CONST_A_PARENT);
288             var parentXML = null;
289             if (parentName) {
290                 //parentXML = armatureXML.querySelectorAll(ccs.CONST_ARMATURE+" > "+ccs.CONST_BONE);
291                 for (var j = 0; j < bonesXML.length; j++) {
292                     parentXML = bonesXML[j];
293                     if (parentName == bonesXML[j].getAttribute(ccs.CONST_A_NAME)) {
294                         //todo
295                         break;
296                     }
297                 }
298             }
299             var boneData = this.decodeBone(boneXML, parentXML, dataInfo);
300             armatureData.addBoneData(boneData);
301         }
302         return armatureData;
303     },
304 
305     decodeBone: function (boneXML, parentXML, dataInfo) {
306 
307         var name = boneXML.getAttribute(ccs.CONST_A_NAME);
308         if (name == "") {
309             return;
310         }
311         var boneData = new ccs.BoneData();
312         boneData.name = name;
313         boneData.parentName = boneXML.getAttribute(ccs.CONST_A_PARENT) || "";
314         boneData.zOrder = parseInt(boneXML.getAttribute(ccs.CONST_A_Z)) || 0;
315 
316         var displaysXML = boneXML.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_DISPLAY);
317 
318         var displayXML;
319         for (var i = 0; i < displaysXML.length; i++) {
320             displayXML = displaysXML[i];
321             var displayData = this.decodeBoneDisplay(displayXML, dataInfo);
322             boneData.addDisplayData(displayData);
323         }
324         return boneData;
325     },
326     decodeBoneDisplay: function (displayXML, dataInfo) {
327         var isArmature = parseFloat(displayXML.getAttribute(ccs.CONST_A_IS_ARMATURE)) || 0;
328         var displayData = null;
329 
330         if (isArmature == 1) {
331             displayData = new ccs.ArmatureDisplayData();
332             displayData.displayType = ccs.DISPLAY_TYPE_ARMATURE;
333         }
334         else {
335             displayData = new ccs.SpriteDisplayData();
336             displayData.displayType = ccs.DISPLAY_TYPE_SPRITE;
337         }
338         var displayName = displayXML.getAttribute(ccs.CONST_A_NAME) || "";
339         if (displayName) {
340             displayData.displayName = displayName;
341         }
342         return displayData;
343     },
344 
345 
346     decodeAnimation: function (animationXML, dataInfo) {
347         var name = animationXML.getAttribute(ccs.CONST_A_NAME);
348         var aniData = new ccs.AnimationData();
349         var armatureData = ccs.armatureDataManager.getArmatureData(name);
350         aniData.name = name;
351 
352         var movementsXML = animationXML.querySelectorAll(ccs.CONST_ANIMATION + " > " + ccs.CONST_MOVEMENT);
353         var movementXML = null;
354         for (var i = 0; i < movementsXML.length; i++) {
355             movementXML = movementsXML[i];
356             var movementData = this.decodeMovement(movementXML, armatureData, dataInfo);
357             aniData.addMovement(movementData);
358         }
359         return aniData;
360     },
361 
362     decodeMovement: function (movementXML, armatureData, dataInfo) {
363         var movName = movementXML.getAttribute(ccs.CONST_A_NAME);
364         var movementData = new ccs.MovementData();
365         movementData.name = movName;
366         var duration, durationTo, durationTween, loop = 0, tweenEasing = 0;
367 
368         duration = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION)) || 0;
369         movementData.duration = duration;
370 
371         durationTo = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION_TO)) || 0;
372         movementData.durationTo = durationTo;
373 
374         durationTween = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION_TWEEN)) || 0;
375         movementData.durationTween = durationTween;
376 
377         loop = movementXML.getAttribute(ccs.CONST_A_LOOP);
378         movementData.loop = loop ? Boolean(parseFloat(loop)) : true;
379 
380         var easing = movementXML.getAttribute(ccs.CONST_A_TWEEN_EASING);
381         if (easing) {
382             if (easing != ccs.CONST_FL_NAN) {
383                 tweenEasing = parseFloat(easing) || 0;
384                 movementData.tweenEasing = tweenEasing == 2 ? ccs.TweenType.sineEaseInOut : tweenEasing;
385             } else {
386                 movementData.tweenEasing = ccs.TweenType.linear;
387             }
388         }
389 
390         var movBonesXml = movementXML.querySelectorAll(ccs.CONST_MOVEMENT + " > " + ccs.CONST_BONE);
391         var movBoneXml = null;
392         for (var i = 0; i < movBonesXml.length; i++) {
393             movBoneXml = movBonesXml[i];
394             var boneName = movBoneXml.getAttribute(ccs.CONST_A_NAME);
395 
396             if (movementData.getMovementBoneData(boneName)) {
397                 continue;
398             }
399 
400             var boneData = armatureData.getBoneData(boneName);
401             var parentName = boneData.parentName;
402 
403             var parentXML = null;
404             if (parentName != "") {
405                 for (var j = 0; j < movBonesXml.length; j++) {
406                     parentXML = movBonesXml[j];
407                     if (parentName == parentXML.getAttribute(ccs.CONST_A_NAME)) {
408                         break;
409                     }
410                 }
411             }
412             var moveBoneData = this.decodeMovementBone(movBoneXml, parentXML, boneData, dataInfo);
413             movementData.addMovementBoneData(moveBoneData);
414         }
415         return movementData;
416     },
417 
418     decodeMovementBone: function (movBoneXml, parentXml, boneData, dataInfo) {
419         var movBoneData = new ccs.MovementBoneData();
420         var scale, delay;
421 
422         if (movBoneXml) {
423             scale = parseFloat(movBoneXml.getAttribute(ccs.CONST_A_MOVEMENT_SCALE)) || 0;
424             movBoneData.scale = scale;
425 
426             delay = parseFloat(movBoneXml.getAttribute(ccs.CONST_A_MOVEMENT_DELAY)) || 0;
427             if (delay > 0) {
428                 delay -= 1;
429             }
430             movBoneData.delay = delay;
431         }
432 
433         var length = 0;
434         var parentTotalDuration = 0;
435         var currentDuration = 0;
436         var parentFrameXML = null;
437         var parentXMLList = [];
438 
439         //*  get the parent frame xml list, we need get the origin data
440         if (parentXml != null) {
441             var parentFramesXML = parentXml.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_FRAME);
442             for (var i = 0; i < parentFramesXML.length; i++) {
443                 parentXMLList.push(parentFramesXML[i]);
444             }
445             length = parentXMLList.length;
446         }
447 
448 
449         var totalDuration = 0;
450 
451         var name = movBoneXml.getAttribute(ccs.CONST_A_NAME);
452         movBoneData.name = name;
453         var framesXML = movBoneXml.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_FRAME);
454         var j = 0;
455         for (var ii = 0; ii < framesXML.length; ii++) {
456             var frameXML = framesXML[ii];
457             if (parentXml) {
458                 //*  in this loop we get the corresponding parent frame xml
459                 while (j < length && (parentFrameXML ? (totalDuration < parentTotalDuration || totalDuration >= parentTotalDuration + currentDuration) : true)) {
460                     parentFrameXML = parentXMLList[j];
461                     parentTotalDuration += currentDuration;
462                     currentDuration = parseFloat(parentFrameXML.getAttribute(ccs.CONST_A_DURATION));
463                     j++;
464                 }
465             }
466             var frameData = this.decodeFrame(frameXML, parentFrameXML, boneData, dataInfo);
467             movBoneData.addFrameData(frameData);
468             frameData.frameID = totalDuration;
469             totalDuration += frameData.duration;
470             movBoneData.duration = totalDuration;
471         }
472 
473         //Change rotation range from (-180 -- 180) to (-infinity -- infinity)
474         var frames = movBoneData.frameList;
475         var pi = Math.PI;
476         for (var i = frames.length - 1; i >= 0; i--) {
477             if (i > 0) {
478                 var difSkewX = frames[i].skewX - frames[i - 1].skewX;
479                 var difSkewY = frames[i].skewY - frames[i - 1].skewY;
480 
481                 if (difSkewX < -pi || difSkewX > pi) {
482                     frames[i - 1].skewX = difSkewX < 0 ? frames[i - 1].skewX - 2 * pi : frames[i - 1].skewX + 2 * pi;
483                 }
484 
485                 if (difSkewY < -pi || difSkewY > pi) {
486                     frames[i - 1].skewY = difSkewY < 0 ? frames[i - 1].skewY - 2 * pi : frames[i - 1].skewY + 2 * pi;
487                 }
488             }
489         }
490 
491         if (movBoneData.frameList.length > 0) {
492             var frameData = new ccs.FrameData();
493             frameData.copy(movBoneData.frameList[movBoneData.frameList.length - 1]);
494             frameData.frameID = movBoneData.duration;
495             movBoneData.addFrameData(frameData);
496         }
497         return movBoneData;
498     },
499     decodeFrame: function (frameXML, parentFrameXml, boneData, dataInfo) {
500         var frameData = new ccs.FrameData();
501         frameData.movement = frameXML.getAttribute(ccs.CONST_A_MOVEMENT) || "";
502         frameData.event = frameXML.getAttribute(ccs.CONST_A_EVENT) || "";
503         frameData.blendType = parseInt(frameXML.getAttribute(ccs.CONST_A_BLEND_TYPE)) || ccs.BLEND_TYPE_NORMAL;
504 
505         var blendFunc = frameData.blendFunc;
506         switch (frameData.blendType) {
507             case ccs.BLEND_TYPE_NORMAL:
508                 blendFunc.src = cc.BLEND_SRC;
509                 blendFunc.dst = cc.BLEND_DST;
510                 break;
511             case ccs.BLEND_TYPE_ADD:
512                 blendFunc.src = cc.SRC_ALPHA;
513                 blendFunc.dst = cc.ONE;
514                 break;
515             case ccs.BLEND_TYPE_MULTIPLY:
516                 blendFunc.src = cc.ONE_MINUS_SRC_ALPHA;
517                 blendFunc.dst = cc.ONE_MINUS_DST_COLOR;
518                 break;
519             case ccs.BLEND_TYPE_SCREEN:
520                 blendFunc.src = cc.ONE;
521                 blendFunc.dst = cc.ONE_MINUS_DST_COLOR;
522                 break;
523             default:
524                 break;
525         }
526 
527         frameData.sound = frameXML.getAttribute(ccs.CONST_A_SOUND) || "";
528         frameData.soundEffect = frameXML.getAttribute(ccs.CONST_A_SOUND_EFFECT) || "";
529 
530         var isTween = frameXML.getAttribute(ccs.CONST_A_TWEEN_FRAME);
531         if(isTween == null)
532             isTween = true;
533         frameData.isTween = Boolean(isTween);
534 
535         if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) {
536             frameData.x = parseFloat(frameXML.getAttribute(ccs.CONST_A_COCOS2DX_X)) || 0;
537             frameData.y = -parseFloat(frameXML.getAttribute(ccs.CONST_A_COCOS2DX_Y)) || 0;
538         }
539         else {
540             frameData.x = parseFloat(frameXML.getAttribute(ccs.CONST_A_X)) || 0;
541             frameData.y = -parseFloat(frameXML.getAttribute(ccs.CONST_A_Y)) || 0;
542         }
543         frameData.x *= this._positionReadScale;
544         frameData.y *= this._positionReadScale;
545         frameData.scaleX = parseFloat(frameXML.getAttribute(ccs.CONST_A_SCALE_X)) || 0;
546         frameData.scaleY = parseFloat(frameXML.getAttribute(ccs.CONST_A_SCALE_Y)) || 0;
547         frameData.skewX = cc.degreesToRadians(parseFloat(frameXML.getAttribute(ccs.CONST_A_SKEW_X)) || 0);
548         frameData.skewY = cc.degreesToRadians(-parseFloat(frameXML.getAttribute(ccs.CONST_A_SKEW_Y)) || 0);
549         frameData.duration = parseFloat(frameXML.getAttribute(ccs.CONST_A_DURATION)) || 0;
550         frameData.displayIndex = parseFloat(frameXML.getAttribute(ccs.CONST_A_DISPLAY_INDEX)) || 0;
551         frameData.zOrder = parseFloat(frameXML.getAttribute(ccs.CONST_A_Z)) || 0;
552         frameData.tweenRotate = parseFloat(frameXML.getAttribute(ccs.CONST_A_TWEEN_ROTATION)) || 0;
553 
554         var colorTransformXMLList = frameXML.querySelectorAll(ccs.CONST_FRAME + " > " + ccs.CONST_A_COLOR_TRANSFORM);
555         if (colorTransformXMLList.length > 0) {
556             var colorTransformXML = colorTransformXMLList[0];
557             var alpha = 0, red = 0, green = 0, blue = 0;
558             var alphaOffset = 0, redOffset = 0, greenOffset = 0, blueOffset = 100;
559 
560             alpha = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_ALPHA)) || alpha;
561             red = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_RED)) || red;
562             green = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_GREEN)) || green;
563             blue = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_BLUE)) || blue;
564 
565             var str_alphaOffset = colorTransformXML.getAttribute(ccs.CONST_A_ALPHA_OFFSET);
566             if (str_alphaOffset) {
567                 alphaOffset = parseFloat(str_alphaOffset);
568             }
569             var str_redOffset = colorTransformXML.getAttribute(ccs.CONST_A_RED_OFFSET);
570             if (str_redOffset) {
571                 redOffset = parseFloat(str_redOffset);
572             }
573             var str_greenOffset = colorTransformXML.getAttribute(ccs.CONST_A_GREEN_OFFSET);
574             if (str_redOffset) {
575                 greenOffset = parseFloat(str_greenOffset);
576             }
577             var str_blueOffset = colorTransformXML.getAttribute(ccs.CONST_A_BLUE_OFFSET);
578             if (str_blueOffset) {
579                 blueOffset = parseFloat(str_blueOffset);
580             }
581 
582             frameData.a = 2.55 * alphaOffset + alpha;
583             frameData.r = 2.55 * redOffset + red;
584             frameData.g = 2.55 * greenOffset + green;
585             frameData.b = 2.55 * blueOffset + blue;
586 
587             frameData.isUseColorInfo = true;
588         }
589         if (frameData.displayIndex == -1) {
590             frameData.a = 0;
591         }
592 
593         var tweenEasing = frameXML.getAttribute(ccs.CONST_A_TWEEN_EASING);
594         if (tweenEasing) {
595             if (tweenEasing != ccs.CONST_FL_NAN) {
596                 frameData.tweenEasing = tweenEasing == 2 ? ccs.TweenType.sineEaseInOut : tweenEasing;
597             } else {
598                 frameData.tweenEasing = ccs.TweenType.linear;
599             }
600         }
601 
602         if (parentFrameXml) {
603             //*  recalculate frame data from parent frame data, use for translate matrix
604             var helpNode = new ccs.BaseData();
605             if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) {
606                 helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_X)) || 0;
607                 helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_Y)) || 0;
608             }
609             else {
610                 helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_X)) || 0;
611                 helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_Y)) || 0;
612             }
613             helpNode.skewX = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_X)) || 0;
614             helpNode.skewY = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_Y)) || 0;
615 
616             helpNode.y = -helpNode.y;
617             helpNode.skewX = cc.degreesToRadians(helpNode.skewX);
618             helpNode.skewY = cc.degreesToRadians(-helpNode.skewY);
619             ccs.TransformHelp.transformFromParent(frameData, helpNode);
620         }
621         return frameData;
622     },
623 
624     decodeTexture: function (textureXML, dataInfo) {
625         var textureData = new ccs.TextureData();
626         if (textureXML.getAttribute(ccs.CONST_A_NAME)) {
627             textureData.name = textureXML.getAttribute(ccs.CONST_A_NAME);
628         }
629         var px, py, width, height = 0;
630         if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) {
631             px = parseFloat(textureXML.getAttribute(ccs.CONST_A_COCOS2D_PIVOT_X)) || 0;
632             py = parseFloat(textureXML.getAttribute(ccs.CONST_A_COCOS2D_PIVOT_Y)) || 0;
633         }
634         else {
635             px = parseFloat(textureXML.getAttribute(ccs.CONST_A_PIVOT_X)) || 0;
636             py = parseFloat(textureXML.getAttribute(ccs.CONST_A_PIVOT_Y)) || 0;
637         }
638         width = parseFloat(textureXML.getAttribute(ccs.CONST_A_WIDTH)) || 0;
639         height = parseFloat(textureXML.getAttribute(ccs.CONST_A_HEIGHT)) || 0;
640 
641         var anchorPointX = px / width;
642         var anchorPointY = (height - py) / height;
643 
644         textureData.pivotX = anchorPointX;
645         textureData.pivotY = anchorPointY;
646 
647         var contoursXML = textureXML.querySelectorAll(ccs.CONST_SUB_TEXTURE + " > " + ccs.CONST_CONTOUR);
648         for (var i = 0; i < contoursXML.length; i++) {
649             this.decodeContour(contoursXML[i], dataInfo);
650         }
651         return textureData;
652     },
653 
654     decodeContour: function (contourXML, dataInfo) {
655         var contourData = new ccs.ContourData();
656         var vertexDatasXML = contourXML.querySelectorAll(ccs.CONST_CONTOUR + " > " + ccs.CONST_CONTOUR_VERTEX);
657         var vertexDataXML;
658         for (var i = 0; i < vertexDatasXML.length; i++) {
659             vertexDataXML = vertexDatasXML[i];
660             var vertex = cc.p(0, 0);
661             vertex.x = parseFloat(vertexDataXML.getAttribute(ccs.CONST_A_X)) || 0;
662             vertex.y = parseFloat(vertexDataXML.getAttribute(ccs.CONST_A_Y)) || 0;
663             //vertex.y = - vertex.y;//todo
664             contourData.vertexList.push(vertex);
665         }
666         return contourData;
667 
668     },
669 
670     addDataFromJson: function (filePath, dataInfo, isLoadSpriteFrame) {
671         var fileContent = cc.loader.getRes(filePath);
672         this.addDataFromJsonCache(fileContent, dataInfo, isLoadSpriteFrame);
673     },
674     addDataFromJsonCache: function (dic, dataInfo, isLoadSpriteFrame) {
675         dataInfo.contentScale = dic[ccs.CONST_CONTENT_SCALE] || 1;
676         var armatureDataArr = dic[ccs.CONST_ARMATURE_DATA] || [];
677         var armatureData;
678         for (var i = 0; i < armatureDataArr.length; i++) {
679             armatureData = this.decodeArmatureFromJSON(armatureDataArr[i], dataInfo);
680             ccs.armatureDataManager.addArmatureData(armatureData.name, armatureData, dataInfo.filename);
681         }
682 
683         var animationDataArr = dic[ccs.CONST_ANIMATION_DATA] || [];
684         var animationData;
685         for (var i = 0; i < animationDataArr.length; i++) {
686             animationData = this.decodeAnimationFromJson(animationDataArr[i], dataInfo);
687             ccs.armatureDataManager.addAnimationData(animationData.name, animationData, dataInfo.filename);
688         }
689 
690         var textureDataArr = dic[ccs.CONST_TEXTURE_DATA] || [];
691         var textureData;
692         for (var i = 0; i < textureDataArr.length; i++) {
693             textureData = this.decodeTextureFromJson(textureDataArr[i], dataInfo);
694             ccs.armatureDataManager.addTextureData(textureData.name, textureData, dataInfo.filename);
695         }
696 
697         if (isLoadSpriteFrame) {
698             var configFiles = dic[ccs.CONST_CONFIG_FILE_PATH] || [];
699             var locFilePath, locPos, locPlistPath, locImagePath;
700             for (var i = 0; i < configFiles.length; i++) {
701                 locFilePath = configFiles[i];
702                 locPos = locFilePath.lastIndexOf(".");
703                 locFilePath = locFilePath.substring(0, locPos);
704                 locPlistPath = dataInfo.basefilePath + locFilePath + ".plist";
705                 locImagePath = dataInfo.basefilePath + locFilePath + ".png";
706                 ccs.armatureDataManager.addSpriteFrameFromFile(locPlistPath, locImagePath, dataInfo.filename);
707             }
708         }
709 
710         armatureData = null;
711         animationData = null;
712     },
713 
714     decodeArmatureFromJSON: function (json, dataInfo) {
715         var armatureData = new ccs.ArmatureData();
716 
717         var name = json[ccs.CONST_A_NAME];
718         if (name) {
719             armatureData.name = name;
720         }
721 
722         dataInfo.cocoStudioVersion = armatureData.dataVersion = json[ccs.CONST_VERSION] || 0.1;
723 
724         var boneDataList = json[ccs.CONST_BONE_DATA];
725         for (var i = 0; i < boneDataList.length; i++) {
726             armatureData.addBoneData(this.decodeBoneFromJson(boneDataList[i], dataInfo));
727         }
728         return armatureData;
729     },
730 
731     decodeBoneFromJson: function (json, dataInfo) {
732         var boneData = new ccs.BoneData();
733         this.decodeNodeFromJson(boneData, json, dataInfo);
734         boneData.name = json[ccs.CONST_A_NAME] || "";
735         boneData.parentName = json[ccs.CONST_A_PARENT] || "";
736         var displayDataList = json[ccs.CONST_DISPLAY_DATA] || [];
737         for (var i = 0; i < displayDataList.length; i++) {
738             var locDisplayData = this.decodeBoneDisplayFromJson(displayDataList[i], dataInfo);
739             boneData.addDisplayData(locDisplayData);
740         }
741         return boneData;
742     },
743 
744     decodeBoneDisplayFromJson: function (json, dataInfo) {
745         var displayType = json[ccs.CONST_A_DISPLAY_TYPE] || ccs.DISPLAY_TYPE_SPRITE;
746         var displayData = null;
747         switch (displayType) {
748             case ccs.DISPLAY_TYPE_SPRITE:
749                 displayData = new ccs.SpriteDisplayData();
750                 displayData.displayName = json[ccs.CONST_A_NAME] || "";
751 
752                 var dicArray = json[ccs.CONST_SKIN_DATA] || [];
753                 var dic = dicArray[0];
754                 if (dic) {
755                     var skinData = displayData.skinData;
756                     skinData.x = (dic[ccs.CONST_A_X] || 0) * this._positionReadScale;
757                     skinData.y = (dic[ccs.CONST_A_Y] || 0) * this._positionReadScale;
758                     if (dic[ccs.CONST_A_SCALE_X] !== undefined) {
759                         skinData.scaleX = dic[ccs.CONST_A_SCALE_X];
760                     }
761                     if (dic[ccs.CONST_A_SCALE_Y] !== undefined) {
762                         skinData.scaleY = dic[ccs.CONST_A_SCALE_Y];
763                     }
764                     skinData.skewX = dic[ccs.CONST_A_SKEW_X] || 0;
765                     skinData.skewY = dic[ccs.CONST_A_SKEW_Y] || 0;
766 
767                     skinData.x *= dataInfo.contentScale;
768                     skinData.y *= dataInfo.contentScale;
769                     dic = null;
770                 }
771                 break;
772             case ccs.DISPLAY_TYPE_ARMATURE:
773                 displayData = new ccs.ArmatureDisplayData();
774                 displayData.displayName = json[ccs.CONST_A_NAME] || "";
775                 break;
776             case ccs.DISPLAY_TYPE_PARTICLE:
777                 displayData = new ccs.ParticleDisplayData();
778                 displayData.displayName = dataInfo.basefilePath + json[ccs.CONST_A_PLIST] || "";
779                 break;
780             default:
781                 displayData = new ccs.SpriteDisplayData();
782                 break;
783         }
784 
785         displayData.displayType = displayType;
786 
787         return displayData;
788     },
789 
790     decodeAnimationFromJson: function (json, dataInfo) {
791         var aniData = new ccs.AnimationData();
792         aniData.name = json[ccs.CONST_A_NAME] || "";
793         var movementDataList = json[ccs.CONST_MOVEMENT_DATA] || [];
794         for (var i = 0; i < movementDataList.length; i++) {
795             var locMovementData = this.decodeMovementFromJson(movementDataList[i], dataInfo);
796             aniData.addMovement(locMovementData);
797         }
798         return aniData;
799     },
800 
801     decodeMovementFromJson: function (json, dataInfo) {
802         var movementData = new ccs.MovementData();
803 
804         movementData.loop = json[ccs.CONST_A_LOOP] || false;
805         movementData.durationTween = json[ccs.CONST_A_DURATION_TWEEN] || 0;
806         movementData.durationTo = json[ccs.CONST_A_DURATION_TO] || 0;
807         movementData.duration = json[ccs.CONST_A_DURATION] || 0;
808         if (json[ccs.CONST_A_MOVEMENT_SCALE] !== undefined) {
809             movementData.scale = json[ccs.CONST_A_MOVEMENT_SCALE]
810         }
811         movementData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.linear;
812         movementData.name = json[ccs.CONST_A_NAME] || "";
813 
814         var movementBoneList = json[ccs.CONST_MOVEMENT_BONE_DATA] || [];
815         for (var i = 0; i < movementBoneList.length; i++) {
816             var locMovementBoneData = this.decodeMovementBoneFromJson(movementBoneList[i], dataInfo);
817             movementData.addMovementBoneData(locMovementBoneData);
818         }
819         return movementData;
820     },
821 
822     decodeMovementBoneFromJson: function (json, dataInfo) {
823         var movementBoneData = new ccs.MovementBoneData();
824         movementBoneData.delay = json[ccs.CONST_A_MOVEMENT_DELAY] || 0;
825         if (json[ccs.CONST_A_MOVEMENT_SCALE] !== undefined) {
826             movementBoneData.scale = json[ccs.CONST_A_MOVEMENT_SCALE];
827         }
828 
829         movementBoneData.name = json[ccs.CONST_A_NAME] || "";
830         var frameDataList = json[ccs.CONST_FRAME_DATA] || [];
831         for (var i = 0; i < frameDataList.length; i++) {
832             var frameData = this.decodeFrameFromJson(frameDataList[i], dataInfo);
833             movementBoneData.addFrameData(frameData);
834             if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) {
835                 frameData.frameID = movementBoneData.duration;
836                 movementBoneData.duration += frameData.duration;
837             }
838         }
839 
840         if (dataInfo.cocoStudioVersion < ccs.VERSION_CHANGE_ROTATION_RANGE) {
841             //! Change rotation range from (-180 -- 180) to (-infinity -- infinity)
842             var frames = movementBoneData.frameList;
843             var pi = Math.PI;
844             for (var i = frames.length - 1; i >= 0; i--) {
845                 if (i > 0) {
846                     var difSkewX = frames[i].skewX - frames[i - 1].skewX;
847                     var difSkewY = frames[i].skewY - frames[i - 1].skewY;
848 
849                     if (difSkewX < -pi || difSkewX > pi) {
850                         frames[i - 1].skewX = difSkewX < 0 ? frames[i - 1].skewX - 2 * pi : frames[i - 1].skewX + 2 * pi;
851                     }
852 
853                     if (difSkewY < -pi || difSkewY > pi) {
854                         frames[i - 1].skewY = difSkewY < 0 ? frames[i - 1].skewY - 2 * pi : frames[i - 1].skewY + 2 * pi;
855                     }
856                 }
857             }
858         }
859 
860         if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) {
861             if (movementBoneData.frameList.length > 0) {
862                 var frameData = new ccs.FrameData();
863                 frameData.copy(movementBoneData.frameList[movementBoneData.frameList.length - 1]);
864                 movementBoneData.addFrameData(frameData);
865                 frameData.frameID = movementBoneData.duration;
866             }
867         }
868         return movementBoneData;
869     },
870 
871     decodeFrameFromJson: function (json, dataInfo) {
872         var frameData = new ccs.FrameData();
873         this.decodeNodeFromJson(frameData, json, dataInfo);
874         frameData.duration = json[ccs.CONST_A_DURATION] || 0;
875         frameData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.linear;
876         frameData.displayIndex = json[ccs.CONST_A_DISPLAY_INDEX] || 0;
877 
878         var bd_src = json[ccs.CONST_A_BLEND_SRC] || cc.BLEND_SRC;
879         var bd_dst = json[ccs.CONST_A_BLEND_DST] || cc.BLEND_DST;
880         frameData.blendFunc.src = bd_src;
881         frameData.blendFunc.dst = bd_dst;
882 
883         frameData.event = json[ccs.CONST_A_EVENT] || null;
884         if (json[ccs.CONST_A_TWEEN_FRAME] !== undefined) {
885             frameData.isTween = json[ccs.CONST_A_TWEEN_FRAME]
886         }
887         if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED)
888             frameData.duration = json[ccs.CONST_A_DURATION] || 0;
889         else
890             frameData.frameID = json[ccs.CONST_A_FRAME_INDEX] || 0;
891 
892         var twEPs = json[ccs.CONST_A_EASING_PARAM] || [];
893         for (var i = 0; i < twEPs.length; i++) {
894             var twEP = twEPs[i];
895             frameData.easingParams[i] = twEP;
896         }
897 
898         return frameData;
899     },
900 
901     decodeTextureFromJson: function (json) {
902         var textureData = new ccs.TextureData();
903         textureData.name = json[ccs.CONST_A_NAME] || "";
904         textureData.width = json[ccs.CONST_A_WIDTH] || 0;
905         textureData.height = json[ccs.CONST_A_HEIGHT] || 0;
906         textureData.pivotX = json[ccs.CONST_A_PIVOT_X] || 0;
907         textureData.pivotY = json[ccs.CONST_A_PIVOT_Y] || 0;
908 
909         var contourDataList = json[ccs.CONST_CONTOUR_DATA] || [];
910         for (var i = 0; i < contourDataList.length; i++) {
911             var locContourData = this.decodeContourFromJson(contourDataList[i]);
912             textureData.contourDataList.push(locContourData);
913         }
914         return textureData;
915     },
916 
917     decodeContourFromJson: function (json) {
918         var contourData = new ccs.ContourData();
919         var vertexPointList = json[ccs.CONST_VERTEX_POINT] || [];
920         for (var i = 0; i < vertexPointList.length; i++) {
921             var dic = vertexPointList[i];
922             var vertex = cc.p(0, 0);
923             vertex.x = dic[ccs.CONST_A_X] || 0;
924             vertex.y = dic[ccs.CONST_A_Y] || 0;
925             contourData.vertexList.push(vertex);
926         }
927         return contourData;
928     },
929 
930     decodeNodeFromJson: function (node, json, dataInfo) {
931         node.x = json[ccs.CONST_A_X] || 0;
932         node.y = json[ccs.CONST_A_Y] || 0;
933 
934         node.x *= dataInfo.contentScale;
935         node.y *= dataInfo.contentScale;
936 
937         node.zOrder = json[ccs.CONST_A_Z] || 0;
938 
939         node.skewX = json[ccs.CONST_A_SKEW_X] || 0;
940         node.skewY = json[ccs.CONST_A_SKEW_Y] || 0;
941         if (json[ccs.CONST_A_SCALE_X] !== undefined) {
942             node.scaleX = json[ccs.CONST_A_SCALE_X];
943         }
944         if (json[ccs.CONST_A_SCALE_Y] !== undefined) {
945             node.scaleY = json[ccs.CONST_A_SCALE_Y];
946         }
947 
948         var colorDic = json[ccs.CONST_COLOR_INFO] || null;
949         if (colorDic) {
950             //compatible old version
951             if (dataInfo.cocoStudioVersion < ccs.VERSION_COLOR_READING) {
952                 colorDic = colorDic[0];
953             }
954             node.a = colorDic[ccs.CONST_A_ALPHA];
955             node.r = colorDic[ccs.CONST_A_RED];
956             node.g = colorDic[ccs.CONST_A_GREEN];
957             node.b = colorDic[ccs.CONST_A_BLUE];
958             node.isUseColorInfo = true;
959             delete colorDic;
960         }
961     },
962 
963     removeConfigFile: function (configFile) {
964         cc.arrayRemoveObject(this._configFileList, configFile);
965     }
966 };