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 };