From 536d07a0019097d048d728a1eebbd8d5472e761d Mon Sep 17 00:00:00 2001 From: dingpinglv Date: Wed, 25 Mar 2015 14:32:58 +0800 Subject: [PATCH] Issue #2760: update some spine skeleton APIs, but it doesn't support Mesh. --- extensions/spine/CCSkeleton.js | 50 ++++++-- extensions/spine/CCSkeletonAnimation.js | 124 ++++++++++++++++++- extensions/spine/CCSkeletonWebGLRenderCmd.js | 13 +- extensions/spine/Spine.js | 93 +++++++------- 4 files changed, 216 insertions(+), 64 deletions(-) diff --git a/extensions/spine/CCSkeleton.js b/extensions/spine/CCSkeleton.js index 2a3816a75a..a3c7b402b4 100644 --- a/extensions/spine/CCSkeleton.js +++ b/extensions/spine/CCSkeleton.js @@ -48,15 +48,15 @@ sp.VERTEX_INDEX = { }; /** - * The attachment type of spine. It contains three type: REGION(0), BOUNDING_BOX(1), REGION_SEQUENCE(2) and MESH(2). + * The attachment type of spine. It contains three type: REGION(0), BOUNDING_BOX(1), MESH(2) and SKINNED_MESH. * @constant * @type {{REGION: number, BOUNDING_BOX: number, REGION_SEQUENCE: number, MESH: number}} */ sp.ATTACHMENT_TYPE = { REGION: 0, BOUNDING_BOX: 1, - REGION_SEQUENCE: 2, - MESH: 2 + MESH: 2, + SKINNED_MESH:3 }; /** @@ -112,7 +112,7 @@ sp.Skeleton = cc.Node.extend(/** @lends sp.Skeleton# */{ }, /** - * Sets whether open debug solots. + * Sets whether open debug slots. * @param {boolean} enable true to open, false to close. */ setDebugSolots:function(enable){ @@ -127,12 +127,48 @@ sp.Skeleton = cc.Node.extend(/** @lends sp.Skeleton# */{ this._debugBones = enable; }, + /** + * Sets whether open debug slots. + * @param {boolean} enabled true to open, false to close. + */ + setDebugSlotsEnabled: function(enabled) { + this._debugSlots = enabled; + }, + + /** + * Gets whether open debug slots. + * @returns {boolean} true to open, false to close. + */ + getDebugSlotsEnabled: function() { + return this._debugSlots; + }, + + /** + * Sets whether open debug bones. + * @param {boolean} enabled + */ + setDebugBonesEnabled: function(enabled) { + this._debugBones = enabled; + }, + + /** + * Gets whether open debug bones. + * @returns {boolean} true to open, false to close. + */ + getDebugBonesEnabled: function() { + return this._debugBones; + }, + /** * Sets the time scale of sp.Skeleton. - * @param {Number} v + * @param {Number} scale */ - setTimeScale:function(v){ - this._timeScale = v; + setTimeScale:function(scale){ + this._timeScale = scale; + }, + + getTimeScale: function(){ + return this._timeScale; }, /** diff --git a/extensions/spine/CCSkeletonAnimation.js b/extensions/spine/CCSkeletonAnimation.js index bb00ba2da5..0d1e392a34 100644 --- a/extensions/spine/CCSkeletonAnimation.js +++ b/extensions/spine/CCSkeletonAnimation.js @@ -119,7 +119,7 @@ sp._regionAttachment_updateQuad = function(self, slot, quad, premultipliedAlpha) sp._meshAttachment_updateQuad = function(self, slot, quad, premultipliedAlpha) { var vertices = {}; - self.computeVertices(slot.bone.x, slot.bone.y, slot.bone, vertices); + self.computeWorldVertices(slot.bone.x, slot.bone.y, slot, vertices); var r = slot.bone.skeleton.r * slot.r * 255; var g = slot.bone.skeleton.g * slot.g * 255; var b = slot.bone.skeleton.b * slot.b * 255; @@ -182,6 +182,25 @@ sp.ANIMATION_EVENT_TYPE = { EVENT: 3 }; +sp.TrackEntryListeners = function(startListener, endListener, completeListener, eventListener){ + this.startListener = startListener || null; + this.endListener = endListener || null; + this.completeListener = completeListener || null; + this.eventListener = eventListener || null; +}; + +sp.TrackEntryListeners.getListeners = function(entry){ + if(!entry.rendererObject){ + entry.rendererObject = new sp.TrackEntryListeners(); + entry.listener = sp.trackEntryCallback; + } + return entry.rendererObject; +}; + +sp.trackEntryCallback = function(state, trackIndex, type, event, loopCount) { + state.rendererObject.onTrackEntryEvent(trackIndex, type, event, loopCount); +}; + /** * The skeleton animation of spine. It updates animation's state and skeleton's world transform. * @class @@ -195,12 +214,19 @@ sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ _target: null, _callback: null, + _ownsAnimationStateData: false, + _startListener: null, + _endListener: null, + _completeListener: null, + _eventListener: null, + /** * Initializes a sp.SkeletonAnimation. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. * @override */ init: function () { sp.Skeleton.prototype.init.call(this); + this._ownsAnimationStateData = true; this.setAnimationStateData(new spine.AnimationStateData(this._skeleton.data)); }, @@ -210,6 +236,7 @@ sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ */ setAnimationStateData: function (stateData) { var state = new spine.AnimationState(stateData); + state.rendererObject = this; state.onStart = this._onAnimationStateStart.bind(this); state.onComplete = this._onAnimationStateComplete.bind(this); state.onEnd = this._onAnimationStateEnd.bind(this); @@ -258,10 +285,11 @@ sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ * @param {Number} trackIndex * @param {String} name * @param {Boolean} loop - * @param {Number} delay + * @param {Number} [delay=0] * @returns {spine.TrackEntry|null} */ addAnimation: function (trackIndex, name, loop, delay) { + delay = delay == null ? 0 : delay; var animation = this._skeleton.data.findAnimation(name); if (!animation) { cc.log("Spine: Animation not found:" + name); @@ -302,13 +330,102 @@ sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ */ update: function (dt) { this._super(dt); - dt *= this._timeScale; this._state.update(dt); this._state.apply(this._skeleton); this._skeleton.updateWorldTransform(); }, + /** + * Set the start event listener. + * @param {function} listener + */ + setStartListener: function(listener){ + this._startListener = listener; + }, + + /** + * Set the end event listener. + * @param {function} listener + */ + setEndListener: function(listener) { + this._endListener = listener; + }, + + setCompleteListener: function(listener) { + this._completeListener = listener; + }, + + setEventListener: function(listener){ + this._eventListener = listener; + }, + + setTrackStartListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).startListener = listener; + }, + + setTrackEndListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).endListener = listener; + }, + + setTrackCompleteListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).completeListener = listener; + }, + + setTrackEventListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).eventListener = listener; + }, + + onTrackEntryEvent: function(traceIndex, type, event, loopCount){ + var entry = this._state.getCurrent(traceIndex); + if(!entry.rendererObject) + return; + var listeners = entry.rendererObject; + switch (type){ + case sp.ANIMATION_EVENT_TYPE.START: + if(listeners.startListener) + listeners.startListener(traceIndex); + break; + case sp.ANIMATION_EVENT_TYPE.END: + if(listeners.endListener) + listeners.endListener(traceIndex); + break; + case sp.ANIMATION_EVENT_TYPE.COMPLETE: + if(listeners.completeListener) + listeners.completeListener(traceIndex, loopCount); + break; + case sp.ANIMATION_EVENT_TYPE.EVENT: + if(listeners.eventListener) + listeners.eventListener(traceIndex, event); + break; + } + }, + + onAnimationStateEvent: function(trackIndex, type, event, loopCount) { + switch(type){ + case sp.ANIMATION_EVENT_TYPE.START: + if(this._startListener) + this._startListener(trackIndex); + break; + case sp.ANIMATION_EVENT_TYPE.END: + if(this._endListener) + this._endListener(trackIndex); + break; + case sp.ANIMATION_EVENT_TYPE.COMPLETE: + if(this._completeListener) + this._completeListener(trackIndex, loopCount); + break; + case sp.ANIMATION_EVENT_TYPE.EVENT: + if(this._eventListener) + this._eventListener(trackIndex, event); + break; + } + }, + + getState: function(){ + return this._state; + }, + _onAnimationStateStart: function (trackIndex) { this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.START, null, 0); }, @@ -322,6 +439,7 @@ sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.EVENT, event, 0); }, _animationStateCallback: function (trackIndex, type, event, loopCount) { + this.onAnimationStateEvent(trackIndex, type, event, loopCount); if (this._target && this._callback) { this._callback.call(this._target, this, trackIndex, type, event, loopCount) } diff --git a/extensions/spine/CCSkeletonWebGLRenderCmd.js b/extensions/spine/CCSkeletonWebGLRenderCmd.js index 9b78bbd0eb..83c6aa93da 100644 --- a/extensions/spine/CCSkeletonWebGLRenderCmd.js +++ b/extensions/spine/CCSkeletonWebGLRenderCmd.js @@ -82,11 +82,13 @@ switch(slot.attachment.type) { case sp.ATTACHMENT_TYPE.REGION: - sp._regionAttachment_updateQuad(attachment, slot, quad, node._premultipliedAlpha); - break; + sp._regionAttachment_updateQuad(attachment, slot, quad, node._premultipliedAlpha); + break; case sp.ATTACHMENT_TYPE.MESH: - sp._meshAttachment_updateQuad(attachment, slot, quad, node._premultipliedAlpha); - break; + sp._meshAttachment_updateQuad(attachment, slot, quad, node._premultipliedAlpha); + break; + case sp.ATTACHMENT_TYPE.SKINNED_MESH: + break; } textureAtlas.updateQuad(quad, quadCount); @@ -98,9 +100,8 @@ } if (node._debugBones || node._debugSlots) { - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - //cc.kmGLPushMatrixWitMat4(node._stackMatrix); + //cc.kmGLPushMatrixWitMat4(this._stackMatrix); cc.current_stack.stack.push(cc.current_stack.top); cc.current_stack.top = this._stackMatrix; diff --git a/extensions/spine/Spine.js b/extensions/spine/Spine.js index d76f2c3dac..e29bca57d0 100644 --- a/extensions/spine/Spine.js +++ b/extensions/spine/Spine.js @@ -31,7 +31,9 @@ var spine = { radDeg: 180 / Math.PI, degRad: Math.PI / 180, - temp: [] + temp: [], + Float32Array: (typeof(Float32Array) === 'undefined') ? Array : Float32Array, + Uint16Array: (typeof(Uint16Array) === 'undefined') ? Array : Uint16Array }; spine.BoneData = function (name, parent) { @@ -147,8 +149,8 @@ spine.Bone.prototype = { m11 = -m11; } var invDet = 1 / (m00 * m11 - m01 * m10); - world[0] = (dx * m00 * invDet - dy * m01 * invDet); - world[1] = (dy * m11 * invDet - dx * m10 * invDet); + world[0] = dx * m00 * invDet - dy * m01 * invDet; + world[1] = dy * m11 * invDet - dx * m10 * invDet; }, localToWorld: function (local) { var localX = local[0], localY = local[1]; @@ -224,7 +226,9 @@ spine.IkConstraint.prototype = { spine.IkConstraint.apply1 = function (bone, targetX, targetY, alpha) { var parentRotation = (!bone.data.inheritRotation || !bone.parent) ? 0 : bone.parent.worldRotation; var rotation = bone.rotation; - var rotationIK = Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * spine.radDeg - parentRotation; + var rotationIK = Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * spine.radDeg; + if (bone.worldFlipX != (bone.worldFlipY != spine.Bone.yDown)) rotationIK = -rotationIK; + rotationIK -= parentRotation; bone.rotationIK = rotation + (rotationIK - rotation) * alpha; }; /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The @@ -770,14 +774,11 @@ spine.FfdTimeline.prototype = { this.frameVertices[frameIndex] = vertices; }, apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var slot = skeleton.slots[slotIndex]; - if (slot.attachment != attachment) return; + var slot = skeleton.slots[this.slotIndex]; + if (slot.attachment != this.attachment) return; var frames = this.frames; - if (time < frames[0]) { - slot.attachmentVertices.length = 0; - return; // Time is before first frame. - } + if (time < frames[0]) return; // Time is before first frame. var frameVertices = this.frameVertices; var vertexCount = frameVertices[0].length; @@ -1142,9 +1143,9 @@ spine.Skeleton.prototype = { if (!skin) throw "Skin not found: " + skinName; this.setSkin(skin); }, - /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments - * from the new skin are attached if the corresponding attachment from the old skin was attached. If there was no old skin, - * each slot's setup mode attachment is attached from the new skin. + /** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}. + * Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was + * no old skin, each slot's setup mode attachment is attached from the new skin. * @param newSkin May be null. */ setSkin: function (newSkin) { if (newSkin) { @@ -1336,21 +1337,20 @@ spine.MeshAttachment.prototype = { edges: null, width: 0, height: 0, updateUVs: function () { - var width = regionU2 - regionU, height = regionV2 - regionV; - var n = regionUVs.length; - if (!uvs || uvs.length != n) { - uvs = []; - uvs.length = n; + var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; + var n = this.regionUVs.length; + if (!this.uvs || this.uvs.length != n) { + this.uvs = new spine.Float32Array(n); } - if (regionRotate) { + if (this.regionRotate) { for (var i = 0; i < n; i += 2) { - uvs[i] = regionU + regionUVs[i + 1] * width; - uvs[i + 1] = regionV + height - regionUVs[i] * height; + this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; + this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; } } else { for (var i = 0; i < n; i += 2) { - uvs[i] = regionU + regionUVs[i] * width; - uvs[i + 1] = regionV + regionUVs[i + 1] * height; + this.uvs[i] = this.regionU + this.regionUVs[i] * width; + this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; } } }, @@ -1392,21 +1392,20 @@ spine.SkinnedMeshAttachment.prototype = { edges: null, width: 0, height: 0, updateUVs: function (u, v, u2, v2, rotate) { - var width = regionU2 - regionU, height = regionV2 - regionV; - var n = regionUVs.length; - if (!uvs || uvs.length != n) { - uvs = []; - uvs.length = n; + var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; + var n = this.regionUVs.length; + if (!this.uvs || this.uvs.length != n) { + this.uvs = new spine.Float32Array(n); } - if (regionRotate) { + if (this.regionRotate) { for (var i = 0; i < n; i += 2) { - uvs[i] = regionU + regionUVs[i + 1] * width; - uvs[i + 1] = regionV + height - regionUVs[i] * height; + this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; + this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; } } else { for (var i = 0; i < n; i += 2) { - uvs[i] = regionU + regionUVs[i] * width; - uvs[i + 1] = regionV + regionUVs[i + 1] * height; + this.uvs[i] = this.regionU + this.regionUVs[i] * width; + this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; } } }, @@ -1824,8 +1823,8 @@ spine.SkeletonJson.prototype = { var region = this.attachmentLoader.newRegionAttachment(skin, name, path); if (!region) return null; region.path = path; - region.x = (map["x"] || 0) * this.scale; - region.y = (map["y"] || 0) * this.scale; + region.x = (map["x"] || 0) * scale; + region.y = (map["y"] || 0) * scale; region.scaleX = map.hasOwnProperty("scaleX") ? map["scaleX"] : 1; region.scaleY = map.hasOwnProperty("scaleY") ? map["scaleY"] : 1; region.rotation = map["rotation"] || 0; @@ -1870,7 +1869,7 @@ spine.SkeletonJson.prototype = { mesh.path = path; var uvs = this.getFloatArray(map, "uvs", 1); - vertices = this.getFloatArray(map, "vertices", 1); + var vertices = this.getFloatArray(map, "vertices", 1); var weights = []; var bones = []; for (var i = 0, n = vertices.length; i < n; ) { @@ -1907,7 +1906,7 @@ spine.SkeletonJson.prototype = { var attachment = this.attachmentLoader.newBoundingBoxAttachment(skin, name); var vertices = map["vertices"]; for (var i = 0, n = vertices.length; i < n; i++) - attachment.vertices.push(vertices[i] * this.scale); + attachment.vertices.push(vertices[i] * scale); return attachment; } throw "Unknown attachment type: " + type; @@ -2086,16 +2085,16 @@ spine.SkeletonJson.prototype = { vertices.length = vertexCount; var start = valueMap["offset"] || 0; var nn = verticesValue.length; - if (scale == 1) { + if (this.scale == 1) { for (var ii = 0; ii < nn; ii++) vertices[ii + start] = verticesValue[ii]; } else { for (var ii = 0; ii < nn; ii++) - vertices[ii + start] = verticesValue[ii] * scale; + vertices[ii + start] = verticesValue[ii] * this.scale; } if (isMesh) { var meshVertices = attachment.vertices; - for (var ii = 0, nn = vertices.length; ii < nn; i++) + for (var ii = 0, nn = vertices.length; ii < nn; ii++) vertices[ii] += meshVertices[ii]; } } @@ -2186,8 +2185,7 @@ spine.SkeletonJson.prototype = { }, getFloatArray: function (map, name, scale) { var list = map[name]; - var values = []; - values = list.length; + var values = new spine.Float32Array(list.length); var i = 0, n = list.length; if (scale == 1) { for (; i < n; i++) @@ -2200,8 +2198,7 @@ spine.SkeletonJson.prototype = { }, getIntArray: function (map, name) { var list = map[name]; - var values = []; - values = list.length; + var values = new spine.Uint16Array(list.length); for (var i = 0, n = list.length; i < n; i++) values[i] = list[i] | 0; return values; @@ -2428,7 +2425,7 @@ spine.AtlasAttachmentLoader = function (atlas) { }; spine.AtlasAttachmentLoader.prototype = { newRegionAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(name); + var region = this.atlas.findRegion(path); if (!region) throw "Region not found in atlas: " + path + " (region attachment: " + name + ")"; var attachment = new spine.RegionAttachment(name); attachment.rendererObject = region; @@ -2442,7 +2439,7 @@ spine.AtlasAttachmentLoader.prototype = { return attachment; }, newMeshAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(name); + var region = this.atlas.findRegion(path); if (!region) throw "Region not found in atlas: " + path + " (mesh attachment: " + name + ")"; var attachment = new spine.MeshAttachment(name); attachment.rendererObject = region; @@ -2460,7 +2457,7 @@ spine.AtlasAttachmentLoader.prototype = { return attachment; }, newSkinnedMeshAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(name); + var region = this.atlas.findRegion(path); if (!region) throw "Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"; var attachment = new spine.SkinnedMeshAttachment(name); attachment.rendererObject = region; @@ -2628,4 +2625,4 @@ spine.SkeletonBounds.prototype = { getHeight: function () { return this.maxY - this.minY; } -}; +}; \ No newline at end of file