1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4  Copyright (c) 2014 Shengxiang Chen (Nero Chan)
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * @ignore
 29  */
 30 sp._atlasPage_createTexture_webGL = function (self, path) {
 31     var texture = cc.textureCache.addImage(path);
 32     self.rendererObject = cc.TextureAtlas.create(texture, 128);
 33     self.width = texture.getPixelsWide();
 34     self.height = texture.getPixelsHigh();
 35 };
 36 
 37 sp._atlasPage_createTexture_canvas = function(self, path) {
 38     self._texture = cc.textureCache.addImage(path);
 39 };
 40 
 41 sp._atlasPage_disposeTexture = function (self) {
 42     self.rendererObject.release();
 43 };
 44 
 45 sp._atlasLoader = {
 46     spAtlasFile:null,
 47     setAtlasFile:function(spAtlasFile){
 48         this.spAtlasFile = spAtlasFile;
 49     },
 50     load:function(page, line, spAtlas){
 51         var texturePath = cc.path.join(cc.path.dirname(this.spAtlasFile), line);
 52         if (cc._renderType === cc._RENDER_TYPE_WEBGL)
 53             sp._atlasPage_createTexture_webGL(page,texturePath);
 54         else
 55             sp._atlasPage_createTexture_canvas(page,texturePath);
 56     },
 57     unload:function(obj){
 58     }
 59 };
 60 
 61 sp._regionAttachment_computeWorldVertices = function(self, x, y, bone, vertices){
 62     var offset = self.offset;
 63     x += bone.worldX;
 64     y += bone.worldY;
 65     var vertexIndex = sp.VERTEX_INDEX;
 66     vertices[vertexIndex.X1] = offset[vertexIndex.X1] * bone.m00 + offset[vertexIndex.Y1] * bone.m01 + x;
 67     vertices[vertexIndex.Y1] = offset[vertexIndex.X1] * bone.m10 + offset[vertexIndex.Y1] * bone.m11 + y;
 68     vertices[vertexIndex.X2] = offset[vertexIndex.X2] * bone.m00 + offset[vertexIndex.Y2] * bone.m01 + x;
 69     vertices[vertexIndex.Y2] = offset[vertexIndex.X2] * bone.m10 + offset[vertexIndex.Y2] * bone.m11 + y;
 70     vertices[vertexIndex.X3] = offset[vertexIndex.X3] * bone.m00 + offset[vertexIndex.Y3] * bone.m01 + x;
 71     vertices[vertexIndex.Y3] = offset[vertexIndex.X3] * bone.m10 + offset[vertexIndex.Y3] * bone.m11 + y;
 72     vertices[vertexIndex.X4] = offset[vertexIndex.X4] * bone.m00 + offset[vertexIndex.Y4] * bone.m01 + x;
 73     vertices[vertexIndex.Y4] = offset[vertexIndex.X4] * bone.m10 + offset[vertexIndex.Y4] * bone.m11 + y;
 74 };
 75 
 76 /*cc._spCallback = function(state, trackIndex, type,event, loopCount){
 77  state.context.onAnimationStateEvent(trackIndex, type, event, loopCount);
 78  };*/
 79 
 80 sp._regionAttachment_updateQuad = function(self, slot, quad, premultipliedAlpha) {
 81     var vertices = {};
 82     self.computeVertices(slot.skeleton.x, slot.skeleton.y, slot.bone, vertices);
 83     var r = slot.skeleton.r * slot.r * 255;
 84     var g = slot.skeleton.g * slot.g * 255;
 85     var b = slot.skeleton.b * slot.b * 255;
 86     var normalizedAlpha = slot.skeleton.a * slot.a;
 87     if (premultipliedAlpha) {
 88         r *= normalizedAlpha;
 89         g *= normalizedAlpha;
 90         b *= normalizedAlpha;
 91     }
 92     var a = normalizedAlpha * 255;
 93 
 94     quad.bl.colors.r = quad.tl.colors.r = quad.tr.colors.r = quad.br.colors.r = r;
 95     quad.bl.colors.g = quad.tl.colors.g = quad.tr.colors.g = quad.br.colors.g = g;
 96     quad.bl.colors.b = quad.tl.colors.b = quad.tr.colors.b = quad.br.colors.b = b;
 97     quad.bl.colors.a = quad.tl.colors.a = quad.tr.colors.a = quad.br.colors.a = a;
 98 
 99     var VERTEX = sp.VERTEX_INDEX;
100     quad.bl.vertices.x = vertices[VERTEX.X1];
101     quad.bl.vertices.y = vertices[VERTEX.Y1];
102     quad.tl.vertices.x = vertices[VERTEX.X2];
103     quad.tl.vertices.y = vertices[VERTEX.Y2];
104     quad.tr.vertices.x = vertices[VERTEX.X3];
105     quad.tr.vertices.y = vertices[VERTEX.Y3];
106     quad.br.vertices.x = vertices[VERTEX.X4];
107     quad.br.vertices.y = vertices[VERTEX.Y4];
108 
109     quad.bl.texCoords.u = self.uvs[VERTEX.X1];
110     quad.bl.texCoords.v = self.uvs[VERTEX.Y1];
111     quad.tl.texCoords.u = self.uvs[VERTEX.X2];
112     quad.tl.texCoords.v = self.uvs[VERTEX.Y2];
113     quad.tr.texCoords.u = self.uvs[VERTEX.X3];
114     quad.tr.texCoords.v = self.uvs[VERTEX.Y3];
115     quad.br.texCoords.u = self.uvs[VERTEX.X4];
116     quad.br.texCoords.v = self.uvs[VERTEX.Y4];
117 };
118 
119 sp._regionAttachment_updateSlotForCanvas = function(self, slot, points) {
120     if(!points)
121         return;
122 
123     var vertices = {};
124     self.computeVertices(slot.skeleton.x, slot.skeleton.y, slot.bone, vertices);
125     var VERTEX = sp.VERTEX_INDEX;
126     points.length = 0;
127     points.push(cc.p(vertices[VERTEX.X1], vertices[VERTEX.Y1]));
128     points.push(cc.p(vertices[VERTEX.X4], vertices[VERTEX.Y4]));
129     points.push(cc.p(vertices[VERTEX.X3], vertices[VERTEX.Y3]));
130     points.push(cc.p(vertices[VERTEX.X2], vertices[VERTEX.Y2]));
131 };
132 
133 /**
134  * The event type of spine skeleton animation. It contains event types: START(0), END(1), COMPLETE(2), EVENT(3).
135  * @constant
136  * @type {{START: number, END: number, COMPLETE: number, EVENT: number}}
137  */
138 sp.ANIMATION_EVENT_TYPE = {
139     START: 0,
140     END: 1,
141     COMPLETE: 2,
142     EVENT: 3
143 };
144 
145 /**
146  * The skeleton animation of spine. It updates animation's state and skeleton's world transform.
147  * @class
148  * @extends sp.Skeleton
149  * @example
150  * var spineBoy = new sp.SkeletonAnimation('res/skeletons/spineboy.json', 'res/skeletons/spineboy.atlas');
151  * this.addChild(spineBoy, 4);
152  */
153 sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{
154     _state: null,
155     _target: null,
156     _callback: null,
157 
158     /**
159      * Initializes a sp.SkeletonAnimation. please do not call this function by yourself, you should pass the parameters to constructor to initialize it.
160      * @override
161      */
162     init: function () {
163         sp.Skeleton.prototype.init.call(this);
164         this.setAnimationStateData(new spine.AnimationStateData(this._skeleton.data));
165     },
166 
167     /**
168      * Sets animation state data to sp.SkeletonAnimation.
169      * @param {spine.AnimationStateData} stateData
170      */
171     setAnimationStateData: function (stateData) {
172         var state = new spine.AnimationState(stateData);
173         state.onStart = this._onAnimationStateStart.bind(this);
174         state.onComplete = this._onAnimationStateComplete.bind(this);
175         state.onEnd = this._onAnimationStateEnd.bind(this);
176         state.onEvent = this._onAnimationStateEvent.bind(this);
177         this._state = state;
178     },
179 
180     /**
181      * Mix applies all keyframe values, interpolated for the specified time and mixed with the current values.  <br/>
182      * @param {String} fromAnimation
183      * @param {String} toAnimation
184      * @param {Number} duration
185      */
186     setMix: function (fromAnimation, toAnimation, duration) {
187         this._state.data.setMixByName(fromAnimation, toAnimation, duration);
188     },
189 
190     /**
191      * Sets event listener of sp.SkeletonAnimation.
192      * @param {Object} target
193      * @param {Function} callback
194      */
195     setAnimationListener: function (target, callback) {
196         this._target = target;
197         this._callback = callback;
198     },
199 
200     /**
201      * Set the current animation. Any queued animations are cleared.
202      * @param {Number} trackIndex
203      * @param {String} name
204      * @param {Boolean} loop
205      * @returns {spine.TrackEntry|null}
206      */
207     setAnimation: function (trackIndex, name, loop) {
208         var animation = this._skeleton.data.findAnimation(name);
209         if (!animation) {
210             cc.log("Spine: Animation not found: " + name);
211             return null;
212         }
213         return this._state.setAnimation(trackIndex, animation, loop);
214     },
215 
216     /**
217      * Adds an animation to be played delay seconds after the current or last queued animation.
218      * @param {Number} trackIndex
219      * @param {String} name
220      * @param {Boolean} loop
221      * @param {Number} delay
222      * @returns {spine.TrackEntry|null}
223      */
224     addAnimation: function (trackIndex, name, loop, delay) {
225         var animation = this._skeleton.data.findAnimation(name);
226         if (!animation) {
227             cc.log("Spine: Animation not found:" + name);
228             return null;
229         }
230         return this._state.addAnimation(trackIndex, animation, loop, delay);
231     },
232 
233     /**
234      * Returns track entry by trackIndex.
235      * @param trackIndex
236      * @returns {spine.TrackEntry|null}
237      */
238     getCurrent: function (trackIndex) {
239         return this._state.getCurrent(trackIndex);
240     },
241 
242     /**
243      * Clears all tracks of animation state.
244      */
245     clearTracks: function () {
246         this._state.clearTracks();
247     },
248 
249     /**
250      * Clears track of animation state by trackIndex.
251      * @param {Number} trackIndex
252      */
253     clearTrack: function (trackIndex) {
254         this._state.clearTrack(trackIndex);
255     },
256 
257     /**
258      * Update will be called automatically every frame if "scheduleUpdate" is called when the node is "live".
259      * It updates animation's state and skeleton's world transform.
260      * @param {Number} dt Delta time since last update
261      * @override
262      */
263     update: function (dt) {
264         this._super(dt);
265 
266         dt *= this._timeScale;
267         this._state.update(dt);
268         this._state.apply(this._skeleton);
269         this._skeleton.updateWorldTransform();
270     },
271 
272     _onAnimationStateStart: function (trackIndex) {
273         this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.START, null, 0);
274     },
275     _onAnimationStateEnd: function (trackIndex) {
276         this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.END, null, 0);
277     },
278     _onAnimationStateComplete: function (trackIndex, count) {
279         this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.COMPLETE, null, count);
280     },
281     _onAnimationStateEvent: function (trackIndex, event) {
282         this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.EVENT, event, 0);
283     },
284     _animationStateCallback: function (trackIndex, type, event, loopCount) {
285         if (this._target && this._callback) {
286             this._callback.call(this._target, this, trackIndex, type, event, loopCount)
287         }
288     }
289 });
290 
291 /**
292  * Creates a skeleton animation object.
293  * @deprecated since v3.0, please use new sp.SkeletonAnimation(skeletonDataFile, atlasFile, scale) instead.
294  * @param {spine.SkeletonData|String} skeletonDataFile
295  * @param {String|spine.Atlas|spine.SkeletonData} atlasFile atlas filename or atlas data or owns SkeletonData
296  * @param {Number} [scale] scale can be specified on the JSON or binary loader which will scale the bone positions, image sizes, and animation translations.
297  * @returns {sp.Skeleton}
298  */
299 sp.SkeletonAnimation.create = function (skeletonDataFile, atlasFile/* or atlas*/, scale) {
300     return new sp.SkeletonAnimation(skeletonDataFile, atlasFile, scale);
301 };